What's the most intuitive way to calculate the time and space complexity (Big O notation) of the following recursive function?
function count(str) {
if (str.length <= 1) {
return 1;
}
var firstTwoDigits = parseInt(str.slice(0, 2), 10);
if (firstTwoDigits <= 26) {
return count(str.slice(1)) +
count(str.slice(2));
}
return count(str.slice(1));
}
Apologies for my prev answer, Complexity of your code seems to be
O(2^N) or O(2^N-1) to be precise in worst case scenario.
So, If
N = str.length ;//number of iteration
In the worst case scenario, your str consists of all N digits of either 1 or 2.
Then, If N is 20 to begin with, then it will spawn two more recursive calls of N= 18 and N = 19,
Then, N = 19 will spawn two more calls (and so one till value of N is 0 )
So, the number of calls will increase exponentially with each iteration), hence coming to the value (2^N - 1).
Related
UPDATE AT THE BOTTOM OF THE POST!
This is the first part of a program that will eventually make SVG star polygons.
Only star polygons that can be made in one go, I.e. like a Pentagram, NOT like a Hexagram that can only be made with at least 2 shapes I.e. 2 inverted and overlapping triangles.
I'm almost finished with this. Everything seems to be working well and I'm getting the out put I want except there's an empty array item in every other array produced for some reason.
In this part
I'm printing to the console (for testing) an object with items named with numbers that represent the number of points / sides of a regular polygon. Within each item is an array with the lower half of all the non factoring numbers of that item (number) I.e. an array of numbers that when the number (item name) is divided by them, it will return a fraction.
E.g. Object
starPolygons{'5': 2, '7': 3, 2, '8': 3, '9': 4, 2, …}
(Representation of: Pentagon: Heptagon: Octagon: Nonagon: …)
What "qty_test" functions does
The points variable (= 8 for example) is sent to a function (qty_test) which is used to find the number of divisors I need to test and inside it is divided by 2. If the result is a fraction, it will return the result rounded back, and if its even, it will return the result - 1.
//8 has more divisors to cycle through -so its a better example!
//In the real program, it will be 5.
let points = 8;
let starPolygons = {};
E.g. qty_test
point (=8) ()=> n /= 2 (=4)
if n - n(rounded-back) = 0?
true returns (n -1) and false returns n(rounded-back)
function qty_test(n) {
n /= 2;
let divisorQTY = n - Math.floor(n) !== 0;
return divisorQTY ? Math.floor(n) : (n - 1);
};
What divisor_test functions does
This function uses the number returned from the previous function (n) to set a for loop that tests every cycle if n is not a factor of the value of the points variable. I.e. points divided by n returns a fraction and if it returns true, meaning a fraction was produced n`s value is indexed in an array and decreaces by 1 (--n).
E.g. divisor_test
n(=8) / 2 = 4 << 2 will be ignored.
n(=8) / 3 = 2.666... << 3 will be collected
function divisor_test(n) {
let nonFactors = [];
n = qty_test(n);
for (let index = 0; index <= n; index++) {
let quotient = (points / n) - Math.floor(points / n) !== 0;
quotient ? nonFactors[index] = n-- : --n;
};
return nonFactors;
};
The program cycles through 5 - 360 and indexes an object with numbers (5-360) and array list of their lower half non factor numbers.
while (points <= 360) {
nonFactors = divisor_test(points);
let testArray = nonFactors.length;
if (testArray) starPolygons[String(points)] = nonFactors;
points++;
};
console.log(starPolygons);
AS YOU CAN SEE IN THIS IMAGE. THE PATTERN OF EMPTY ARRAY INDEXES / ITEMS
UPDATE: I NOTICED THE PATTERN OF ARRAYS WITH THE EMPTY SLOTS HAS AN INTERESTING QUALITY TO IT. This is so cool and so confusing as to what causes this...
During the Iteration you are forcing the array to add an empty item.
So, the empty object appears when the array has only two items in it and you are trying to nonFactors[3] = n--;
and thats what causes the issue.
So a more simplified version of the for loop with the solution will be
for (let index = 0; index <= n; index++) {
let quotient = (points / n) - Math.floor(points / n) !== 0;
if(quotient){
if(index > nonFactors.length){
nonFactors[index - 1] = n--
}else{
nonFactors[index] = n--
}
}else{
n = n -1;
}
};
I solved my problem
There's an answer here that already explains what causes the problem and also gives a working solution by Nadav Hury (upvote his answer. I bet his answer generally works better in more situations)! So I will just post my own version of a solution.
for (let index = 0; n >= 2; index++) {
let quotient = (points / n) - Math.floor(points / n) !== 0;
if (quotient) nonFactors[index] = n--;
else --n, --index;
};
The culprit is that in the line with checking the quotient
quotient ? nonFactors[index] = n-- : --n;
you added setting the value only for the case when it is present that is equal to true but you didn't add to the case when it is false correct solution is:
quotient ? nonFactors[index] = n-- : nonFactors[index] = --n;.
I have written the function which finds largest prime factor of some number. This function works but the problem is that it is too slow. e.g when I enter 600851475143 as a parameter, the process of finding largest prime factor lasts too long. How can I modify it so that it works faster?
Here is my code:
class test {
static addArray(someArray, member) {
for (var i = 0; i <= someArray.length; i++) {
if (i == someArray.length) {
someArray[i] = member;
return someArray;
}
}
}
static someLength(someArray) {
var i = 0;
while (someArray[i] !== undefined) {
var lastItem = i;
i++;
}
return i;
}
static testPrime(i) {
for (var k=2; k < i; k++) {
if (i % k == 0) {
return false;
}
}
return true;
}
}
var primeArray = [];
function largestPrime(n) {
for (var i=2; i < n; i++) {
//var k = n / i;
if (n % i == 0 && test.testPrime(i) == true) {
test.addArray(primeArray, i);
n == n / i;
}
}
return primeArray[test.someLength(primeArray) - 1];
}
document.write(largestPrime(600851475143));
Alright, before we go into that, let's get a little bit of theory sorted. The way you measure the time a particular piece of code takes to run is, mathematically, denoted by the O(n) notation (big-o notation) where n is the size of the input.
Your test prime function is of something called linear complexity meaning that it'll become linearly slow as the size of n (in this case, your number input) gets large.
For the number 15, the execution context is as follows:
15 % 2 == 0 (FALSE)
15 % 3 == 0 (TRUE)
...
15 % 14 == 0 (FALSE)
This means that for the number 100, there will be 98 (2 - 99) steps. And this will grow with time. Let's take your number into consideration: 600851475143. The program will execute 600851475143; the for-loop will get triggered 600,851,475,141 times.
Now, let's consider a clock cycle. Say each instruction takes 1 clock cycle, and a dumbed down version of your loop takes 2, the number 600851475143 will execute 1,201,702,950,286 times. Consider each clock cycle takes 0.0000000625 seconds (for a 16-MHz platform such as the Arduino), the time taken by that code alone is:
0.0000000625 * 1201702950286 = ~75,106 seconds
Or around 20 hours.
You see where I am going with this.
Your best best to get this program to work faster is to use a probabilistic test and confirm your findings using this number (or a BigInteger variant thereof).
Your approach is more linear, in the sense that the number of iterations for the for-loop to check for primality increases with an increasing number. You can plot the CPU cycle time along with the number and you'll realize that this is a rather inefficient way to do this.
I have discrete mathematics at my Uni, so just a word of warning - primality tests and their variants get really messy as you get into the utopia of faster and faster tests. It's a path filled with thorns of mathematics and you should have a seat belt while riding through the jungle! ;)
If you need more information on this, I would be glad to assist! I hope this helped! :)
I'm trying to solve all the lessons on codility but I failed to do so on the following problem: Ladder by codility
I've searched all over the internet and I'm not finding a answer that satisfies me because no one answers why the max variable impacts so much the result.
So, before posting the code, I'll explain the thinking.
By looking at it I didn't need much time to understand that the total number of combinations it's a Fibonacci number, and removing the 0 from the Fibonacci array, I'd find the answer really fast.
Now, afterwards, they told that we should return the number of combinations modulus 2^B[i].
So far so good, and I decided to submit it without the var max, then I got a score of 37%.. I searched all over the internet and the 100% result was similar to mine but they added that max = Math.pow(2,30).
Can anyone explain to me how and why that max influences so much the score?
My Code:
// Powers 2 to num
function pow(num){
return Math.pow(2,num);
}
// Returns a array with all fibonacci numbers except for 0
function fibArray(num){
// const max = pow(30); -> Adding this max to the fibonaccy array makes the answer be 100%
const arr = [0,1,1];
let current = 2;
while(current<=num){
current++;
// next = arr[current-1]+arr[current-2] % max;
next = arr[current-1]+arr[current-2]; // Without this max it's 30 %
arr.push(next);
}
arr.shift(); // remove 0
return arr;
}
function solution(A, B) {
let f = fibArray(A.length + 1);
let res = new Array(A.length);
for (let i = 0; i < A.length; ++i) {
res[i] = f[A[i]] % (pow(B[i]));
}
return res;
}
console.log(solution([4,4,5,5,1],[3,2,4,3,1])); //5,1,8,0,1
// Note that the console.log wont differ in this solution having max set or not.
// Running the exercise on Codility shows the full log with all details
// of where it passed and where it failed.
The limits for input parameters are:
Assume that:
L is an integer within the range [1..50,000];
each element of array A is an integer within the range [1..L];
each element of array B is an integer within the range [1..30].
So the array f in fibArray can be 50,001 long.
Fibonacci numbers grow exponentially; according to this page, the 50,000th Fib number has over 10,000 digits.
Javascript does not have built-in support for arbitrary precision integers, and even doubles only offer ~14 s.f. of precision. So with your modified code, you will get "garbage" values for any significant value of L. This is why you only got 30%.
But why is max necessary? Modulo math tells us that:
(a + b) % c = ([a % c] + [b % c]) % c
So by applying % max to the iterative calculation step arr[current-1] + arr[current-2], every element in fibArray becomes its corresponding Fib number mod max, without any variable exceeding the value of max (or built-in integer types) at any time:
fibArray[2] = (fibArray[1] + fibArray[0]) % max = (F1 + F0) % max = F2 % max
fibArray[3] = (F2 % max + F1) % max = (F2 + F1) % max = F3 % max
fibArray[4] = (F3 % max + F2 % max) = (F3 + F2) % max = F4 % max
and so on ...
(Fn is the n-th Fib number)
Note that as B[i] will never exceed 30, pow(2, B[i]) <= max; therefore, since max is always divisible by pow(2, B[i]), applying % max does not affect the final result.
Here is a python 100% answer that I hope offers an explanation :-)
In a nutshell; modulus % is similar to 'bitwise and' & for certain numbers.
eg any number % 10 is equivalent to the right most digit.
284%10 = 4
1994%10 = 4
FACTS OF LIFE:
for multiples of 2 -> X % Y is equivalent to X & ( Y - 1 )
precomputing (2**i)-1 for i in range(1, 31) is faster than computing everything in B when super large arrays are given as args for this particular lesson.
Thus fib(A[i]) & pb[B[i]] will be faster to compute than an X % Y style thingy.
https://app.codility.com/demo/results/trainingEXWWGY-UUR/
And for completeness the code is here.
https://github.com/niall-oc/things/blob/master/codility/ladder.py
Here is my explanation and solution in C++:
Compute the first L fibonacci numbers. Each calculation needs modulo 2^30 because the 50000th fibonacci number cannot be stored even in long double, it is so big. Since INT_MAX is 2^31, the summary of previously modulo'd numbers by 2^30 cannot exceed that. Therefore, we do not need to have bigger store and/or casting.
Go through the arrays executing the lookup and modulos. We can be sure this gives the correct result since modulo 2^30 does not take any information away. E.g. modulo 100 does not take away any information for subsequent modulo 10.
vector<int> solution(vector<int> &A, vector<int> &B)
{
const int L = A.size();
vector<int> fibonacci_numbers(L, 1);
fibonacci_numbers[1] = 2;
static const int pow_2_30 = pow(2, 30);
for (int i = 2; i < L; ++i) {
fibonacci_numbers[i] = (fibonacci_numbers[i - 1] + fibonacci_numbers[i - 2]) % pow_2_30;
}
vector<int> consecutive_answers(L, 0);
for (int i = 0; i < L; ++i) {
consecutive_answers[i] = fibonacci_numbers[A[i] - 1] % static_cast<int>(pow(2, B[i]));
}
return consecutive_answers;
}
Hi there I have been researching and trying to learn hw to check for the time complexity of certain algorithms.
I've seen this video which was very helpful.
That being said I wondered off and started trying to work out the Worsts Case and average case of certain algorithms.
Program #1: This is a calculator which calculates in RPN format.
function evaluate() {
var input = prompt("Please enter your input string\n\nExamples of input strings:\n\n\t1. 10 4 5 + *\n\t2. 10 4 5 + * 2 +\n\t3. 10 8 *");
var values = input.split(" ");
var array = new Array();
for (i in values) {
if (values[i] != "+" && values[i] != "*" && values[i] != "-" && values[i] != "/") {
array.push(parseInt(values[i]));
} else {
var operator = values[i];
var val2 = array.pop();
var val1 = array.pop();
switch (operator) {
case "+":
array.push(eval("val1 + val2"));
break;
case "*":
array.push(eval("val1 * val2"));
break;
case "-":
array.push(eval("val1 - val2"));
break;
case "/":
array.push(eval("val1 / val2"));
break;
}
}
}
if (input == "" || input == null) {
document.writeln("Oops, based on your input we have nothing to calculate for you!");
} else {
document.writeln("Your RPN calculation is: ");
document.writeln(array + " with a starting input string of: " + input);
}
}
From what I've understood in this case the the for loop in this case is running for a constant number of times and that is the length of the array then performs a O(1) instruction hence the function reduce has a Time Complexity of O(1) no matter the size of the array passed.
Program #2: Check whether the number is Prime or Not
function isPrime(num) {
if(num <= 1) return false;
const limit = Math.floor(Math.sqrt(num));
for(let i = 2; i <= limit; i++) {
if(num % i === 0) return false;
}
return true;
}
Since there is one for loop and the program needs to at least look at every number from 2 to the inputted number hence I think it is O(n).
For now these are the one's I've done with lots of thinking and am hoping they are correct. My question is there an easy way on how to check the time complexity of functions I've never seen before.
P.S I THINK they are correct. Please if they aren't specify which and why.
Thanks for your help :)
Update
Apparently I was wrong and lexicore corrected me the answers are:
#1 No, it is not O(1). Assuming one step takes O(1) and you have n steps where n is the length of the array, time complexity is O(n).
#2 No, it is not O(n). You cycle makes at most sqrt(n) steps, each step
O(1) so time complexity is O(sqrt(n)) here.
That being said I tried further and stumbled upon this in my textbook. It basically calculates an approximate square root.
#3
function sqrt(num) {
guess = num / 3;
do {
lastGuess = guess;
guess = (num / guess + guess) / 2;
while(Math.abs(lastGuess - guess));
return guess; /
Am I correct to say this is O(n) my reasoning is since we loop until an approx is found.
#4 from the user thanksd in the link he calculates the largest number in an array. Is it safe to say that the time complexity in this is O(n) since the largest number may be at the very last, and hence why O(n).
Thanks again
No, it is not O(1). Assuming one step takes O(1) and you have n steps where n is the length of the array, time complexity is O(n).
No, it is not O(n). You cycle makes at most sqrt(n) steps, each step O(1) so time complexity is O(sqrt(n)) here.
goal: take a number like 54321, add the numbers together (5+4+3+2+1 = 15), then take that number (15) add the digits (1+5 = 6), so return 6;
here is my code:
function digital_root(n) {
if (n >=10) {
var digits = n.toString().split('').map(function(item, index) {return parseInt(item)}).reduce(function(a,b){ return a+b});
console.log(digits);
}
}
digital_root(1632)
Can't figure out: How to get that function to repeat over and over until digits is just one number (i.e. less than 10). I have tried a variety of nested functions, but can't seem to get it right.
If possible please point me in the direction to the solution ("try a nesting in a while... or read up on..."), but don't give me the complete code solution ("Use this code chunk:...."). I've developed a bad habit of just reading and copying...
Thank you!
Try this: reference HERE
function digital_root(n) {
var singlesum = 0;
while (n >= 10 ) {
singlesum=0;
while (n > 0) {
var rem;
rem = n % 10;
singlesum = singlesum + rem;
n = parseInt(n / 10);
}
n = singlesum;
}
console.log(singlesum);
}
digital_root(1632)
You can use recursion to solve this.
Write a function makeSingleDigit, which argument will be your number.
You need a base condition with the base step, which in your case stops the recursion when received number is one-digit and returns the number.
If condition is not true, you just need to get another digit from the number by n%10 and sum it with the makeSingleDigit(Math.floor(n/10)). By this, you repeatedly sum digits of new numbers, until function receives one-digit number.
Mathematical solution just for your information: the number, which you want to find is n % 9 === 0 ? 9 : n % 9, thus it is the remainder of the division by 9 if it is not 0, otherwise it is 9.
Here is a very optimal solution to the problem:
function digital_root(n) {
return (n - 1) % 9 + 1;
}
const result = digital_root(1632);
console.log(result);
Well, not a very good solution but you can give a hit.
function digital_root(n) {
if (n >=10) {
var digits = n.toString().split('').map(function(item, index) {return parseInt(item)}).reduce(function(a,b){ return a+b});
console.log(digits);
return(digits);
}
}
var num = 1632;
do{
num = digital_root(num);
}while(num>10);