Fast GCF algorithm using linked list - algorithm

I am using a 2 linked list to represent 2 very long integers, each digit occupy one node. I need to compute for their gcf fast but my current algorithm computes for a very long time. Please help me improve it/or if you can suggest other faster algorithms for linked list.
here's my current code:
int findGCD(number **larger, number **small, number **gcdtop){
number *a = *larger, *b = *small, *aptr, *bptr;
printlist(larger);
printlist(small);
int equal = checkEqual(a, b); //traverse through linked list a & b and compare if equal, returns 1 if true
int large=0, borrow=0, adata=0, bdata=0, i=0;
while(equal!=1){
equal = checkEqual(a, b);
if(equal==1) break;
flip(&a); //Flips the linked list
flip(&b);
large = whatGreater(&a, &b); //Checks which linkedlist is greater
flip(&a); //Flip it back
flip(&b);
borrow=0;
//Do repeated subtraction (Euclid's algorithm)
if(large==1){
aptr = a;
bptr = b;
while(a && b){
adata = a->data;
bdata = b->data;
adata = adata - borrow;
if(adata>=bdata){
a->data = (adata-bdata);
borrow=0;
}
else if(adata<bdata){
adata = adata+10;
a->data = (adata-bdata);
borrow = 1;
}
a = a->next;
b = b->next;
}
a = aptr;
b = bptr;
}
else if(large==0){
aptr = a;
bptr = b;
while(a && b){
adata = a->data;
bdata = b->data;
bdata = bdata - borrow;
if(bdata>=adata){
b->data = (bdata-adata);
borrow=0;
}
else if(bdata<adata){
bdata = bdata+10;
b->data = (bdata-adata);
borrow = 1;
}
a = a->next;
b = b->next;
}
a = aptr;
b = bptr;
}
}
I believe doing this division/modulo would be faster but I cannot implement it in linked list.
Here's a sample input: 15424832369192002264032565635067237193339888184999832384884463019917546384661904, 65227
Thank you in advance.

Related

How can I make sure my RNG numbers are unique?

I'm trying to select 2 random items out of a list using the RNG class. The problem is occasionally I get the same 2 numbers and I'd like them to be unique. I tried using a while loop to get another number if the it's the same as the last one but adding even a simple while loop results in an "Exceeded prepaid gas" error. What am I not understanding?
//simplified for posting question
var lengthOfList = 10
var numItemsWanted = 2
//Get more rng numbers than I need incase of duplicates
const rng = new RNG<u32>(lenghtOfList, lengthOfList)
for(let i = 0; i < numItemsWanted; i++) {
var r = rng.next()
while (r == rng.last()) {
r = rng.next()
}
newList.push(oldList[r])
}
Working:
//simplified for posting question
var lengthOfList = 10
var numItemsWanted = 2
//Get more rng numbers than I need incase of duplicates
const rng = new RNG<u32>(lenghtOfList, lengthOfList)
let r = rng.next()
let last = r + 1
for(let i = 0; i < numItemsWanted; i++) {
newList.push(oldList[r])
last = r
r = rng.next()
while (r == last) {
r = rng.next()
}
}
this is about near-sdk-as, the smart contract development kit for AssemblyScript on the NEAR platform
you can see how RNG is used in this example
https://github.com/Learn-NEAR/NCD.L1.sample--lottery/blob/ff6cddaa8cac4d8fe29dd1a19b38a6e3c7045363/src/lottery/assembly/lottery.ts#L12-L13
class Lottery {
private chance: f64 = 0.20
play(): bool {
const rng = new RNG<u32>(1, u32.MAX_VALUE);
const roll = rng.next();
logging.log("roll: " + roll.toString());
return roll <= <u32>(<f64>u32.MAX_VALUE * this.chance);
}
}
and how the constructor is implemented here:
https://github.com/near/near-sdk-as/blob/f3707a1672d6da6f6d6a75cd645f8cbdacdaf495/sdk-core/assembly/math.ts#L152
the first argument is the length of the buffer holding random numbers generated from the seed. you can use the next() method to get more numbers from this buffer with each call
export class RNG<T> {
constructor(len: u32, public max: u32 = 10_000) {
let real_len = len * sizeof<T>();
this.buffer = math.randomBuffer(real_len);
this._last = this.get(0);
}
next(): T {}
}
If you remove the item from oldList once picked, it would be imposible to picked it again.
Another aproach is to shuffle your oldList and then pick the first two items.

Paper cut algorithm

I want to create a function to determine the most number of pieces of paper on a parent paper size
The formula above is still not optimal. If using the above formula will only produce at most 32 cut/sheet.
I want it like below.
This seems to be a very difficult problem to solve optimally. See http://lagrange.ime.usp.br/~lobato/packing/ for a discussion of a 2008 paper claiming that the problem is believed (but not proven) to be NP-hard. The researchers found some approximation algorithms and implemented them on that website.
The following solution uses Top-Down Dynamic Programming to find optimal solutions to this problem. I am providing this solution in C#, which shouldn't be too hard to convert into the language of your choice (or whatever style of pseudocode you prefer). I have tested this solution on your specific example and it completes in less than a second (I'm not sure how much less than a second).
It should be noted that this solution assumes that only guillotine cuts are allowed. This is a common restriction for real-world 2D Stock-Cutting applications and it greatly simplifies the solution complexity. However, CS, Math and other programming problems often allow all types of cutting, so in that case this solution would not necessarily find the optimal solution (but it would still provide a better heuristic answer than your current formula).
First, we need a value-structure to represent the size of the starting stock, the desired rectangle(s) and of the pieces cut from the stock (this needs to be a value-type because it will be used as the key to our memoization cache and other collections, and we need to to compare the actual values rather than an object reference address):
public struct Vector2D
{
public int X;
public int Y;
public Vector2D(int x, int y)
{
X = x;
Y = y;
}
}
Here is the main method to be called. Note that all values need to be in integers, for the specific case above this just means multiplying everything by 100. These methods here require integers, but are otherwise are scale-invariant so multiplying by 100 or 1000 or whatever won't affect performance (just make sure that the values don't overflow an int).
public int SolveMaxCount1R(Vector2D Parent, Vector2D Item)
{
// make a list to hold both the item size and its rotation
List<Vector2D> itemSizes = new List<Vector2D>();
itemSizes.Add(Item);
if (Item.X != Item.Y)
{
itemSizes.Add(new Vector2D(Item.Y, Item.X));
}
int solution = SolveGeneralMaxCount(Parent, itemSizes.ToArray());
return solution;
}
Here is an example of how you would call this method with your parameter values. In this case I have assumed that all of the solution methods are part of a class called SolverClass:
SolverClass solver = new SolverClass();
int count = solver.SolveMaxCount1R(new Vector2D(2500, 3800), new Vector2D(425, 550));
//(all units are in tenths of a millimeter to make everything integers)
The main method calls a general solver method for this type of problem (that is not restricted to just one size rectangle and its rotation):
public int SolveGeneralMaxCount(Vector2D Parent, Vector2D[] ItemSizes)
{
// determine the maximum x and y scaling factors using GCDs (Greastest
// Common Divisor)
List<int> xValues = new List<int>();
List<int> yValues = new List<int>();
foreach (Vector2D size in ItemSizes)
{
xValues.Add(size.X);
yValues.Add(size.Y);
}
xValues.Add(Parent.X);
yValues.Add(Parent.Y);
int xScale = NaturalNumbers.GCD(xValues);
int yScale = NaturalNumbers.GCD(yValues);
// rescale our parameters
Vector2D parent = new Vector2D(Parent.X / xScale, Parent.Y / yScale);
var baseShapes = new Dictionary<Vector2D, Vector2D>();
foreach (var size in ItemSizes)
{
var reducedSize = new Vector2D(size.X / xScale, size.Y / yScale);
baseShapes.Add(reducedSize, reducedSize);
}
//determine the minimum values that an allowed item shape can fit into
_xMin = int.MaxValue;
_yMin = int.MaxValue;
foreach (var size in baseShapes.Keys)
{
if (size.X < _xMin) _xMin = size.X;
if (size.Y < _yMin) _yMin = size.Y;
}
// create the memoization cache for shapes
Dictionary<Vector2D, SizeCount> shapesCache = new Dictionary<Vector2D, SizeCount>();
// find the solution pattern with the most finished items
int best = solveGMC(shapesCache, baseShapes, parent);
return best;
}
private int _xMin;
private int _yMin;
The general solution method calls a recursive worker method that does most of the actual work.
private int solveGMC(
Dictionary<Vector2D, SizeCount> shapeCache,
Dictionary<Vector2D, Vector2D> baseShapes,
Vector2D sheet )
{
// have we already solved this size?
if (shapeCache.ContainsKey(sheet)) return shapeCache[sheet].ItemCount;
SizeCount item = new SizeCount(sheet, 0);
if ((sheet.X < _xMin) || (sheet.Y < _yMin))
{
// if it's too small in either dimension then this is a scrap piece
item.ItemCount = 0;
}
else // try every way of cutting this sheet (guillotine cuts only)
{
int child0;
int child1;
// try every size of horizontal guillotine cut
for (int c = sheet.X / 2; c > 0; c--)
{
child0 = solveGMC(shapeCache, baseShapes, new Vector2D(c, sheet.Y));
child1 = solveGMC(shapeCache, baseShapes, new Vector2D(sheet.X - c, sheet.Y));
if (child0 + child1 > item.ItemCount)
{
item.ItemCount = child0 + child1;
}
}
// try every size of vertical guillotine cut
for (int c = sheet.Y / 2; c > 0; c--)
{
child0 = solveGMC(shapeCache, baseShapes, new Vector2D(sheet.X, c));
child1 = solveGMC(shapeCache, baseShapes, new Vector2D(sheet.X, sheet.Y - c));
if (child0 + child1 > item.ItemCount)
{
item.ItemCount = child0 + child1;
}
}
// if no children returned finished items, then the sheet is
// either scrap or a finished item itself
if (item.ItemCount == 0)
{
if (baseShapes.ContainsKey(item.Size))
{
item.ItemCount = 1;
}
else
{
item.ItemCount = 0;
}
}
}
// add the item to the cache before we return it
shapeCache.Add(item.Size, item);
return item.ItemCount;
}
Finally, the general solution method uses a GCD function to rescale the dimensions to achieve scale-invariance. This is implemented in a static class called NaturalNumbers. I have included the rlevant parts of this class below:
static class NaturalNumbers
{
/// <summary>
/// Returns the Greatest Common Divisor of two natural numbers.
/// Returns Zero if either number is Zero,
/// Returns One if either number is One and both numbers are >Zero
/// </summary>
public static int GCD(int a, int b)
{
if ((a == 0) || (b == 0)) return 0;
if (a >= b)
return gcd_(a, b);
else
return gcd_(b, a);
}
/// <summary>
/// Returns the Greatest Common Divisor of a list of natural numbers.
/// (Note: will run fastest if the list is in ascending order)
/// </summary>
public static int GCD(IEnumerable<int> numbers)
{
// parameter checks
if (numbers == null || numbers.Count() == 0) return 0;
int first = numbers.First();
if (first <= 1) return 0;
int g = (int)first;
if (g <= 1) return g;
int i = 0;
foreach (int n in numbers)
{
if (i == 0)
g = n;
else
g = GCD(n, g);
if (g <= 1) return g;
i++;
}
return g;
}
// Euclidian method with Euclidian Division,
// From: https://en.wikipedia.org/wiki/Euclidean_algorithm
private static int gcd_(int a, int b)
{
while (b != 0)
{
int t = b;
b = (a % b);
a = t;
}
return a;
}
}
Please let me know of any problems or questions you might have with this solution.
Oops, forgot that I was also using this class:
public class SizeCount
{
public Vector2D Size;
public int ItemCount;
public SizeCount(Vector2D itemSize, int itemCount)
{
Size = itemSize;
ItemCount = itemCount;
}
}
As I mentioned in the comments, it would actually be pretty easy to factor this class out of the code, but it's still in there right now.

Trying TRIE DS implementation

So, I'tried implementing TRIE DS, and while the node in the tree gets the value of Words assigned after addWord ends, but when I traverse the tree, The value that prints is zero. What did I do wrong, unable to point out. Please can someone help.
#include<iostream>
#include<string>
using namespace std;
struct trie{
int words;
int prefixes;
trie* edges[26];
};
void addWord(trie* vertex, string word){
if(word.length() == 0){
vertex->words = vertex->words + 1;
}
else{
// cout<<word<<endl;
vertex->prefixes = vertex->prefixes + 1;
char k = word[0];
if(vertex->edges[k - 'a'] == NULL){
trie *n = (trie*)malloc(sizeof(trie));
n->words = 0;
n->prefixes = 0;
for(int i=0;i<26;i++)
vertex->edges[i] = NULL;
vertex->edges[k - 'a'] = n;
}
word.erase(0, 1);
addWord(vertex->edges[k - 'a'], word);
}
};
void traverse(trie *vertex){
if(vertex != NULL){
for(int i=0;i<26;i++){
if(vertex->edges[i] != NULL){
traverse(vertex->edges[i]);
cout<<char(i+'a')<<" - "<<vertex->prefixes<< " : "<<vertex->words<<endl;
}
}
}
};
int main(){
string word = "hello";
trie* head = (trie*)malloc(sizeof(trie));
for(int i=0;i<26;i++)
head->edges[i] = NULL;
head->words = 0;
head->prefixes = 0;
addWord(head, word);
string s = "lo";
traverse(head);
return 0;
}
There are two issues with code:
In your addWord function, inside else block, in the for loop, change vertex->edges[i] = NULL; to n->edges[i] = NULL;
The problem you asked for is in your traverse function. You are not printing the words count for node pointed by say last o, you are printing it for the node that have o as it's edge. So just change this:
cout<<char(i+'a')<<" - "<<vertex->prefixes<< " : "<<vertex->words<<endl;
to this:
cout<<char(i+'a')<<" - "<<vertex->edges[i]->prefixes<< " : "<<vertex->edges[i]->words<<endl;

Karatsuba algorithm

I keep getting these errors when I run my program, can anyone spot the mistake? I am not experienced with using recursion and I might have messed up base case. My testing consists of two numbers of the same length, and my goal is to multiply two Big numbers without using the built in class. The method add just takes in two strings which are numbers and adds them, I checked and it works no matter how big the numbers are.
Error NumberFormatException: For input string: ""
Integer.parseInt(Integer.java:592)
public static String mu (String value1, String value2){
int length1 = value1.length();
int length2 = value2.length();
//If one value has more digits than the other, add zeroes to the front...
int temp1;
int temp2;
int multiply;
if (length1==1 || length2 ==1){
temp1 = Integer.parseInt(value1);
temp2 = Integer.parseInt(value2);
multiply = temp1*temp2;
return multiply +"" ;
}else if (length1 ==0 || length2 ==0){
return "";
}
int firstHalf = length1/2;
int secondHalf = length1 - firstHalf;
String value1First = value1.substring(0, firstHalf);
String value1Second = value1.substring(firstHalf, secondHalf);
String value2First = value2.substring(0, firstHalf);
String value2Second = value2.substring(firstHalf, secondHalf);
String ac = mu (value1First, value2First);
String ad = mu (value1First, value2Second);
String bc = mu(value1Second, value2First);
String bd = mu(value1Second, value2Second);
String zeroesToAdd= null;
String zeroesToAdd2 = null;
for (int i=0; i<length1; i++){
zeroesToAdd = "0"+ zeroesToAdd;
}
for (int i=0; i<length1/2; i++){
zeroesToAdd2 = "0"+ zeroesToAdd2;
}
String firstPart = ac + zeroesToAdd;
String secondPart = (add(ad,bc))+zeroesToAdd2;
String thirdPart = bd;
String add1 = add(firstPart, secondPart);
String add2;
return add(add1, thirdPart);
}
Error NumberFormatException: For input string: ""
Integer.parseInt(Integer.java:592)
is caused by the code
Integer.parseInt(value1) or
Integer.parseInt(value2)
You might want to try add more cases for combination of str lengths (1,1) (1,0) (0,1) (0,0). Following code might help!
if (length1==1 && length2 ==1){
temp1 = Integer.parseInt(value1);
temp2 = Integer.parseInt(value2);
multiply = temp1*temp2;
return multiply +"" ;
}else if (length1 ==0 && length2 ==0){
return "";
}
else if (length1 ==0 && length2 ==1){
return value2;
}
else if (length1 ==1 && length2 ==0){
return value1;
}
Hope it helps!

Parsing morse code

I am trying to solve this problem.
The goal is to determine the number of ways a morse string can be interpreted, given a dictionary of word.
What I did is that I first "translated" words from my dictionary into morse. Then, I used a naive algorithm, searching for all the ways it can be interpreted recursively.
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <iterator>
using namespace std;
string morse_string;
int morse_string_size;
map<char, string> morse_table;
unsigned int sol;
void matches(int i, int factor, vector<string> &dictionary) {
int suffix_length = morse_string_size-i;
if (suffix_length <= 0) {
sol += factor;
return;
}
map<int, int> c;
for (vector<string>::iterator it = dictionary.begin() ; it != dictionary.end() ; it++) {
if (((*it).size() <= suffix_length) && (morse_string.substr(i, (*it).size()) == *it)) {
if (c.find((*it).size()) == c.end())
c[(*it).size()] = 0;
else
c[(*it).size()]++;
}
}
for (map<int, int>::iterator it = c.begin() ; it != c.end() ; it++) {
matches(i+it->first, factor*(it->second), dictionary);
}
}
string encode_morse(string s) {
string ret = "";
for (unsigned int i = 0 ; i < s.length() ; ++i) {
ret += morse_table[s[i]];
}
return ret;
}
int main() {
morse_table['A'] = ".-"; morse_table['B'] = "-..."; morse_table['C'] = "-.-."; morse_table['D'] = "-.."; morse_table['E'] = "."; morse_table['F'] = "..-."; morse_table['G'] = "--."; morse_table['H'] = "...."; morse_table['I'] = ".."; morse_table['J'] = ".---"; morse_table['K'] = "-.-"; morse_table['L'] = ".-.."; morse_table['M'] = "--"; morse_table['N'] = "-."; morse_table['O'] = "---"; morse_table['P'] = ".--."; morse_table['Q'] = "--.-"; morse_table['R'] = ".-."; morse_table['S'] = "..."; morse_table['T'] = "-"; morse_table['U'] = "..-"; morse_table['V'] = "...-"; morse_table['W'] = ".--"; morse_table['X'] = "-..-"; morse_table['Y'] = "-.--"; morse_table['Z'] = "--..";
int T, N;
string tmp;
vector<string> dictionary;
cin >> T;
while (T--) {
morse_string = "";
cin >> morse_string;
morse_string_size = morse_string.size();
cin >> N;
for (int j = 0 ; j < N ; j++) {
cin >> tmp;
dictionary.push_back(encode_morse(tmp));
}
sol = 0;
matches(0, 1, dictionary);
cout << sol;
if (T)
cout << endl << endl;
}
return 0;
}
Now the thing is that I only have 3 seconds of execution time allowed, and my algorithm won't work under this limit of time.
Is this the good way to do this and if so, what am I missing ? Otherwise, can you give some hints about what is a good strategy ?
EDIT :
There can be at most 10 000 words in the dictionary and at most 1000 characters in the morse string.
A solution that combines dynamic programming with a rolling hash should work for this problem.
Let's start with a simple dynamic programming solution. We allocate an vector which we will use to store known counts for prefixes of morse_string. We then iterate through morse_string and at each position we iterate through all words and we look back to see if they can fit into morse_string. If they can fit then we use the dynamic programming vector to determine how many ways we could have build the prefix of morse_string up to i-dictionaryWord.size()
vector<long>dp;
dp.push_back(1);
for (int i=0;i<morse_string.size();i++) {
long count = 0;
for (int j=1;j<dictionary.size();j++) {
if (dictionary[j].size() > i) continue;
if (dictionary[j] == morse_string.substring(i-dictionary[j].size(),i)) {
count += dp[i-dictionary[j].size()];
}
}
dp.push_back(count);
}
result = dp[morse_code.size()]
The problem with this solution is that it is too slow. Let's say that N is the length of morse_string and M is the size of the dictionary and K is the size of the largest word in the dictionary. It will do O(N*M*K) operations. If we assume K=1000 this is about 10^10 operations which is too slow on most machines.
The K cost came from the line dictionary[j] == morse_string.substring(i-dictionary[j].size(),i)
If we could speed up this string matching to constant or log complexity we would be okay. This is where rolling hashing comes in. If you build a rolling hash array of morse_string then the idea is that you can compute the hash of any substring of morse_string in O(1). So you could then do hash(dictionary[j]) == hash(morse_string.substring(i-dictionary[j].size(),i))
This is good but in the presence of imperfect hashing you could have multiple words from the dictionary with the same hash. That would mean that after getting a hash match you would still need to match the strings as well as the hashes. In programming contests, people often assume perfect hashing and skip the string matching. This is often a safe bet especially on a small dictionary. In case it doesn't produce a perfect hashing (which you can check in code) you can always adjust your hash function slightly and maybe the adjusted hash function will produce a perfect hashing.

Resources