would like to ask about a JavaScript function.
I don't understand below function, I thought at line 4 fib(n-1) will return 1 and the latter fib(n-2) will return 0, and then they both add together as 1.
May I know why the final result for f(10); will be 55, can't get my head around this.
Anyone can help to explain to me what happening behind the scene, please?
Thanks! ;)
var f = function fib(n) {
if (n === 0) return 0;
if (n === 1) return 1;
if (n > 1) return fib(n - 1) + fib(n - 2); // *2
};
f(10); // 55
ref: https://slides.com/concise/js/fullscreen#/35
Like this. This is a typical recursive function, with two base cases and one recursive step.
Remember that if n is 10, then fib(n - 1) is fib(9), and so on:
fib(10) = fib(9) + fib(8) = 34 + 21 = 55
fib(9) = fib(8) + fib(7) = 21 + 13 = 34
fib(8) = fib(7) + fib(6) = 13 + 8 = 21
fib(7) = fib(6) + fib(5) = 8 + 5 = 13
fib(6) = fib(5) + fib(4) = 5 + 3 = 8
fib(5) = fib(4) + fib(3) = 3 + 2 = 5
fib(4) = fib(3) + fib(2) = 2 + 1 = 3
fib(3) = fib(2) + fib(1) = 1 + 1 = 2
fib(2) = fib(1) + fib(0) = 1 + 0 = 1
fib(1) = 1
fib(0) = 0
Side note: Although your example is a good illustration of recursive functions, it's an extremely inefficient way to calculate fibonacci numbers. A much better approach is to use memoization to eliminate the bulk of the inefficiency:
var fib = (function () {
var cache = [0, 1];
return function fib(num) {
if (!(num in cache)) {
cache[num] = fib(num - 1) + fib(num - 2);
}
return cache[num];
};
})();
console.log(fib(10));
http://jsperf.com/fibonacci-memoization-2015-04-01
this is called "recursive function" which one function calls itself.
basically there is no restriction (in terms of the OS) of doing so, a function basically gets interpreted/compiled to assembly code , and this assembly code can be copied and re-run with different (or the same) arguments.
Related
I'm trying to explain correctly cached fibonacci algorithm complexity. Here is the code (https://jsfiddle.net/msthhbgy/2/):
function allFib(n) {
var memo = [];
for (var i = 0; i < n; i++) {
console.log(i + ":" + fib(i, memo))
}
}
function fib(n, memo) {
if (n < 0) return 0;
else if (n === 1) return 1;
else if (memo[n]) return memo[n];
memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
return memo[n];
}
allFib(5);
The solution is taken from "Cracking the coding interview" and adapted to javascript.
So here is a "not very nice" tree of function calls
I was thinking like that: "The left most branch (bold one) is where the evaluation is happening" and it is definitely the number passed to the allFib function for the first time. So the complexity is O(n). Everything that is to the right will be taken from cache and will not require extra function calls". is it correct? also how to connect this to the tree "theory". The depth and the height of the tree in this case is 4 but not 5 (close to n but not it). I want the answer to be not intuitive but more reliable.
Here is a function that really uses the cache:
function Fibonacci() {
var memo = [0, 1];
this.callCount = 0;
this.calc = function(n) {
this.callCount++;
return n <= 0 ? 0
: memo[n] || (memo[n] = this.calc(n - 1) + this.calc(n - 2));
}
}
var fib = new Fibonacci();
console.log('15! = ', fib.calc(15));
console.log('calls made: ', fib.callCount);
fib.callCount = 0; // reset counter
console.log('5! = ', fib.calc(5));
console.log('calls made: ', fib.callCount);
fib.callCount = 0;
console.log('18! = ', fib.calc(18));
console.log('calls made: ', fib.callCount);
The number of function calls made is:
(n - min(i,n))*2+1
Where i is the last entry in memo.
This you can see as follows with the example of n = 18 and i = 15:
The calls are made in this order:
calc(18)
calc(17) // this.calc(n-1) with n=18
calc(16) // this.calc(n-1) with n=17
calc(15) // this.calc(n-1) with n=16, this can be returned from memo
calc(14) // this.calc(n-2) with n=16, this can be returned from memo
calc(15) // this.calc(n-2) with n=17, this can be returned from memo
calc(16) // this.calc(n-2) with n=18, this can be returned from memo
The general pattern is that this.calc(n-1) and this.calc(n-2) are called just as many as times (of course), with in addition the original call calc(n).
Here is an animation for when you call fib.calcfor the first time as fib.calc(5). The arrows show the calls that are made. The more to the left, the deeper the recursion. The bubbles are colored when the corresponding result is stored in memo:
This evidently is O(n) when i is a given constant.
First, check for negative n, and move the value to zero.
Then check if a value is cached, take the value. If not, assign the value to the cache and return the result.
For the special cases of n === 0 or n === 1 assign n.
function fibonacci(number) {
function f(n) {
return n in cache ?
cache[n] :
cache[n] = n === 0 || n === 1 ? n : f(n - 1) + f(n - 2);
}
var cache = [];
return f(number);
}
console.log(fibonacci(15));
console.log(fibonacci(5));
Part with predefined values in cache, as Thomas suggested.
function fibonacci(number) {
function f(n) {
return n in cache ?
cache[n] :
cache[n] = f(n - 1) + f(n - 2);
}
var cache = [0, 1];
return f(number);
}
console.log(fibonacci(15));
console.log(fibonacci(5));
I was given a code challenge to do that was related to recursion and was unable to complete it. My experience with these types of questions is very slim and this one just stumped me. Could any of you help me out just for my own education, as I've already failed the challenge?
The description:
Given a string of numbers and operators, print out all the different ways you can add parentheses to force the order of operations to be explicit, and the result for running the operations in that order.
Assume:
No weird inputs, everything is separated by one space.
Supported operators are +, *, -, = (for the = operator, if the values are the same return 1, otherwise return 0)
Print your results sorted numerically
Don't worry about the input expression size being too large
Your code should be written in javascript
Don't use eval or external libraries
Example:
node test.js "2 - 1 - 1"
((2-1)-1) = 0
(2-(1-1)) = 2
node test.js "2 * 3 - 4 * 5";
(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10
node test.js "2 + 2 = 2"
((2+2)=2) = 0
(2+(2=2)) = 3
This is where I'm at so far. I'm far from getting the right output, but I feel like the logic is starting to get there. I've adapted this code from a similar, but different question.
var args = process.argv.slice(2)[0].split(" "),
numberOfOperators = 0;
args.forEach(function(val, index, array) {
if (isNaN(val)) {
++numberOfOperators;
}
});
args = args.join("");
var recurse = function(openParenCount, closeParenCount, input, pointer) {
if (openParenCount === 0 && closeParenCount === 0) {
console.log(input + "\n");
}
if (openParenCount > 0) {
input = input.slice(0, pointer) + "(" + input.slice(pointer, input.length);
recurse(openParenCount - 1, closeParenCount + 1, input, pointer+1);
}
if (closeParenCount > 0) {
input = input.slice(0, pointer+openParenCount+3) + ")" + input.slice(pointer+openParenCount+3, input.length+1);
recurse(openParenCount, closeParenCount - 1, input, pointer+3);
}
}
recurse(numberOfOperators, 0, args, 0);
a little hint:
var AP = [];
var input = process.argv.slice(2)[0];
var args = input.replace(/\s+/g, "").split(/([^\d\.]+)/g);
recurse(args, []).forEach(function(v){ console.log(v); });
function recurse(arr, into){
if(arr.length === 1){
into.push(arr[0]);
}else{
for(var i=0, j=arr.length-2; i<j; i+=2){
recurse(
AP.concat(
arr.slice(0, i),
"(" + arr.slice(i, i+3).join(" ") + ")",
arr.slice(i+3)
),
into
)
}
}
return into
}
This Implementation still has a few "bugs", and these by intent; I'm not going to do your "homework".
If you have more than 2 operators in your Equasion, the result will contain duplicates, 2nd It is not sorted, and since it is just splitting and concatenating strings, it can't compute any result.
But it shows you a way how you can implement the recursion.
I would need to determin the Big O of this short code:
var iterations = 0;
function operation(num){
iterations++;
if (num == 0) return 1;
return operation(Math.floor((num / 10) * 2));
}
var result = operation(1000);
alert('Result = ' + result + ', number of iterations = ' + iterations);
I came up with something around O(log(logN)) but I'm not sure. Would you please help me a bit?
http://jsfiddle.net/qotbu5pq/2/
[Answer from comment]
you are almost dividing operations by 5 until hit the zero result
so should not it be ~log5(N) iterations instead which means O(log(N))
sorry didn't want to add such trivial answer ...
newbie in javascript closure
i follow a example from internet, and try to change some of it
i think it should give me 16,17,18,19
but the result was unexpect
here is my code.
i do not know why i first call bar2(10),it alert 17, does it should give me 18?
function foo(x) {
var tmp = 3;
return function (y) {
alert(x + y + (++tmp));
}
}
var bar = foo(2);
bar(10);//alert16
bar(10);//alert17
var bar2 = foo(3);
bar2(10);//alert17
bar2(10);//alert18
Because tmp is a variable local to the function you return from foo -- that means when you call foo for the second time, it gets reset to 3. 3 + (3+1) + 10 = 17.
The result 17 is correct.
Each call to foo produces a new function with a new closed-over variable tmp.
Perhaps you thought the second call to foo uses the same tmp as in the first call? It doesn't. That is why you get 17: 3 + 10 + 4.
bar(y) = n = x + y + tmp
bar(10) = 16 = 2 + 10 + 4
bar(10) = 17 = 2 + 10 + 5
bar2(10) = 17 = 3 + 10 + 4
bar2(10) = 18 = 3 + 10 + 5
i have this two recursive functions in javascript.
first function returns digits of the input number in right to left order
second function returns them in left to right order.
function first(n){
if(n > 0){
m = Math.floor( n/10 );
v = ( n - m * 10 ) + " " + first(m);
return v;
}
return "";
}
function second(n){
if(n > 0){
m = Math.floor( n/10 );
v = second(m) + " " + ( n - m * 10 );
return v;
}
return "";
}
result of the first function is
7 6 1
result of the second function is
1 16 167
but I expected this
1 6 7
I tested similar code in PHP and JAVA and it works well.
Presumably the problem is in Javascript's closures. But I cant figure how to fix it.
It's perfectly simple: You're using implied globals:
function second(n)
{
if(n > 0)
{
m = Math.floor( n/10 );
//m is changing here ------\\will use lowest value of m
v = second(m) + " " + ( n - m * 10 );
return v;
}
return "";
}
The fix is:
function second(n)
{
if(n > 0)
{
//make declare it in the scope itself
var m = Math.floor( n/10 );
v = second(m) + " " + ( n - m * 10 );
return v;
}
return "";
}
This still leaves you with the evil implied global v, too. If I were you, I'd declare v locally, too
function second(n)
{
var m, v = '';
n = +(n);//coerce to number
if (n > 0)
{
m = Math.floor(n/10);
v = second(m) + ' '+ (n-m*10);
}
return v;
}
This function works as expected.
The problem didn't really have to do with closures as such, but it was caused by the way JS resolves expressions/names.
Couple that to how JS deals with recursive functions and you get the output you got, plain and simple.
JS doesn't really have a recursive call-stack, yet. Last time I checked, recursive calls were effectively short-circuited (~= goto's). I remember reading something on the subject by Douglas Crockford, about it having something to do with the call-stack.
Though ES5's strict mode does introduce TCO, and it should make it by the end of 2013 (ES6 - Harmony). I've linked to a couple of sites here, if you care to read more on the matter