I eventually want to get the hang of dynamic programming but before that, I am having a hard time understanding the flow of this. I understand recursion but I'm having trouble understanding the flow of this:
function fib(n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fib(n - 1) + fib(n - 2);
}
console.log(fib(3));
if I have a small integer of 3, it does not pass those 2 conditionals so it hits return fib(n-1)+fib(n-2); So to my understanding, that will go through the first part of that first: fib(n-1) (3-1 = 2)... 2 does not satisfy either of those conditionals so it runs fib(n-1) (2-1 = 1). 1 DOES satisfy one of the conditionals so it returns 1 and breaks that part of it.
Now to to the next part: fib(n-2) . (3-2 = 1). 1 does satisfy one of the conditionals so it returns 1 .
So in the end, isn't that returning 1 + 1 ?
I'm not sure where I'm going wrong in my understanding.
You are correct in that fib(3) should return 2, because 2 is the 3rd number in the Fibonacci sequence (starting at 0)
It helps to write out it out as tree:
fib(3)
/ \
fib(2) fib(1)
/ \ \
fib(1) fib(0) 1
/ \
1 0
above you can see how each recursive call goes all the way to 0 or 1 before returning a result back up the previous layer.
One of my favorite ways to do this is to start with the base cases and go backwards:
fib(0); // => 0
fib(1); // => 1
Then we get to the default case:
fib(2); // == fib(1) + fib(0) == 1 + 0 ==> 1
fib(3); // == fib(2) + fib(1) == 1 + 1 ==> 2
fib(4); // == fib(3) + fib(2) == 2 + 1 ==> 3
This is much easier than trying to figure out fib(4) first since you need to nest. Looking at the function it's easy to see what to try.
Also know that calls to the same function doesn't get any special treatment. It runs until it returns with a value and it's arguments and local variables are local to the call so every fib call has its own n and it waits for the two calls to return to sum the results.
Related
I have the following function fn(n).
function fn(n) {
if (n < 0) return 0;
if (n < 2) return n;
return fn(n - 1) + fn(n - 2);
}
I understand how this code works, but don't how to calculate time complexity for it.
Let’s do some examples:
For n = 3, you have 5 function calls. First fn(3), which in turn calls fn(2) and fn(1) and so on.
For n = 4, you have 9 function calls. First fn(4), which in turn calls fn(3) and fn(2) and so on.
Graphical representation of the 2 examples:
The leftmost nodes go down in descending order: fn(4), fn(3), fn(2), fn(1), which means that the height of the tree (or the number of levels) on the tree will be n.
The time complexity of this code is 2^n - 1. Although, if we count all calls will be just 9 calls for n = 4.
And the question is how we get 2^n - 1? I don't understand
One of the ways of calculating recursive algorithm's time complexity is using the Recursion Tree Method. For this particular case, we can write T(n)=T(n-1)+T(n-2)+2*O(1), where O(1) means constant time, since we have two comparison checks of n values using if. The recursion tree would look something like this:
1 n
2 (n-1) (n-2)
4 (n-2) (n-3) (n-3) (n-4)
8 (n-3)(n-4) (n-4)(n-5) (n-4)(n-5) (n-5)(n-6)
...
2^i for i-th level
Total work done will be the sum of all of the work done in each level, so we can write T(n)=1 + 2 + 4 + 8 + 16 + 32 + ... = 2^0 + 2^1 + 2^2 + 2^3 + 2^4 + ... + 2^i. This is a geometric series which means that the T(n) is equal to (1-2^n)/(1-2) = (1-2^n)/(-1) = 2^n - 1. Because of that the time complexity of the function fn(n) is O(2^n).
You could also approach this using Back Substitution method. We know the following:
T(0)=1
T(1)=1
T(2)=1
T(n)=T(n-1)+T(n-2)+2*O(n)≈2*T(n-1)
Substituting T(n-2) with T(n-1) is allowed. In doing so you will get a higher bound which is still true for T(n-1)+T(n-2).
After the substitution you can also write T(n-1)=2*T(n-2), T(n-2)=2*T(n-3), ...
Using these values and substituting them recursively in to the T(n) you will get:
T(n)=2*2*T(n-2)
=2*2*2*T(n-3)
=2*2*2*2*T(n-4)
=...
=2^i * T(n-i)
From there you can write n-i=1 => i=n-1 and substitute the i value in T(n). You can do this because T(1)=1 is one of the base conditions.
=> T(i)=2^(n-1) * T(n-(n-1))=2^(n-1) * T(n-n+1)=2^(n-1) * T(1)=2^(n-1)
This means that the time complexity is O(2^n).
I have a simple question about JavaScript algorithm
https://www.codewars.com/kata/56747fd5cb988479af000028/train/javascript
I'm solving this problem. The explanation of this problem is to extract two letters from the middle of the odd-numbered character
What I'm curious about is
function getMiddle(s) {
//Code goes here!
let answer = "";
if (s.length % 2 !== 0) {
answer += s[Math.floor(s.length / 2)];
} } else {
answer += s.slice(
(Math.floor(s.length / 2 - 1), Math.floor(s.length / 2 + 1))
);
}
return answer;
}
console.log(getMiddle("test"));
console.log(
"test".slice(
Math.floor("test".length / 2 - 1),
Math.floor("test".length / 2 + 1)
)
);
Is the return value from the getMiddle function different from the console.log('test'.slice~') in the end?
The difference is that one is the return value of the function and the other is just taken directly from the console, but I don't know why it's the same code, but the value is differentcrying
please help me
The problem is that in the function you have wrapped the pair of indices in parentheses:
answer += s.slice(
(Math.floor(s.length / 2 - 1), Math.floor(s.length / 2 + 1))
// ^ ^
);
Those parentheses will trigger an evaluation of what is between them, and that means the comma is then interpreted as a comma-operator. The result of that operation is then a single number that is passed as argument to s.slice. So you are actually calling slice with just one argument instead of two, and due to the comma operator, it is the second index that is used by slice. It is equivalent to s.slice(3)
In the second console.log you don't have those extra parentheses, and so there it works as it is intended.
NB: I assume the extra closing brace just before else is a typo.
function f(num) {
if (num<1) {
return 1;
}
return f(num-1) + f(num-2);
}
f(5); // 13
I investigated this code in the debugger but it's still unclear to me how it works. I see it as some kind of recursion, but don't get it at all.
Any kind of help will be appreciated.
There are essentially two forms of recursion direct and indirect. However, in either case any proper form of recursion must abide by three rules which makes it recursive.
1.) A recursive algorithm must have a base case.
2.) A recursive algorithm must change its state and move toward the base case.
3.) A recursive algorithm must call itself, recursively.
The intention for using a recursion algorithms focuses on taking a relatively mid to large problems and breaking them into smaller problems which can be solved iteratively or until the "base case" condition has been proven true.
function f(num) {
if (num<=1) { // (1) Base case condition
return 1; // (2.b) moving forward once the base case is true
}
// (3) the function calling itself
// also (2.a) changed state - (i.e., the param value is being decremented or "unwound" with each pass of recursion (i.e., method call)
return f(num-1) + f(num-2);
}
f(5); // Fn = Fn-1 + Fn-2 (Fibonacci Number Series)
Resources:
https://www.geeksforgeeks.org/recursion/
https://medium.com/launch-school/recursive-fibonnaci-method-explained-d82215c5498e
https://www.khanacademy.org/computing/computer-science/algorithms/recursive-algorithms/a/the-factorial-function
https://www.khanacademy.org/computing/computer-science/algorithms/recursive-algorithms/a/recursive-factorial
https://runestone.academy/runestone/books/published/pythonds/Recursion/TheThreeLawsofRecursion.html
https://www.natashatherobot.com/recursion-factorials-fibonacci-ruby/
It is a simple recursion implementation of calculating the num-th Fibonacci number(1 1 2 3 5 8....). And it has a small bug. It should be:
function f(num) {
if (num<=1) { // should be <= 1 instead of <, to handle when num = 1, otherwise it'll end up with f(0)+f(-1)
return 1;
}
return f(num-1) + f(num-2);
}
You can try to write down by hand and simulate some simple cases, which I think is really helpful when you study algorithms.
For example:
f(0) -> 0 is less than 1, return 1, thus f(0) = 1
f(1) -> 1 is less than or equal to 1, return 1, thus f(1) = 1
f(2) -> 2 is greater than 1, return f(1) + f(0), which we know from above, is 1 + 1, thus f(2) = 2
f(3) -> 3 is greater than 1, return f(2) + f(1), 2 + 1, thus f(3) = 3
f(4) -> 4 is greater than 1, return f(3) + f(2), 3 + 2, thus f(4) = 5
I bet you see the patterns now. Hope it helps.
It is recursion. It's a fibonacci series. Step through it slowly.
Start with a simple example:
f(0) = 1 (as num <1)
Increase to 1
f(1) = f(0) + f(-1) = 2
(as num = 1, but f(num-1) and f(num-2) are both less than 1 (and so each return 1)
increase to 2:
f(2) = f(2-1) + f(0) = f(1) + f(-1) = 3
we've solved f(1) and f(-1) already so we know the total returned is 2
increase to 3:
f(3) = f(3-1) + f(3-2) = f(2) + f(1) = 3 + 2 = 5
Remembering that the algorithm is expanding out each step fully (not relying on previous solutions so to speak). so this last example would look more like:
f(3) = f(2) + f(1) = (f(1) +f(0)) + (f(0)+f(-1)) = (f(0) + f(-1)) + 1 + 1 + 1 = 1 + 1 + 1 + 1 + 1 = 5
In the example below, I don't want to make a counter as a param. Rather, I just want to return '+ 1' each time so that what gets returned is the number of steps it takes. My issue lies with the base case. If I do return + 1, I get the correct number of steps plus one additional step so I tried just return but that delivers NaN. Is it even possible?
var numberOfSteps = function(num) {
if (num == 0) {
return;
} else {
if (num % 2 == 0) {
return 1 + numberOfSteps(num/2);
} else {
return 1 + numberOfSteps(num - 1);
}
}
};
edit : The goal is to track how many steps it takes to reduce a number to 0. If it's even, divide by 2 or else subtract by 1. Ultimately, I want to return the number of steps it takes for any given number to get reduced to 0 following those rules
I hope the point has gotten through in the long comment thread and other answers that return + 1 is equivalent to return (+1), that is, return the integer positive one. And since there are no steps to take once you've reached zero, +1 is the wrong answer. Similarly, a plain return is functionally equivalent to return undefined. But undefined is not a number, and you're going to run into problems if you later try to add 1 to it. So the solution from the comments or other answers to return the correct number of steps, which in this case 0, will fix your code.
I would like to point out another way to solve this, though:
const numberOfSteps = (n) =>
n <= 0
? 0
: 1 + numberOfSteps (n % 2 == 0 ? n / 2 : n - 1)
console .log (numberOfSteps (12))
There are superficial differences here from the other solutions, such as using an arrow function, using a conditional statement (ternary) rather than if-statements, and using <= 0 instead of < 0 to avoid possible infinite loops on negative numbers.
But the fundamental difference is that this code only has one recursive branch. I think this is a better match to the problem.
We can think of this as a function which answers "How many steps does it take to reach 0 from our input number if each step cuts even numbers in half and subtracts one from odd ones?" Well that logically leads to a base case (we're already at 0) so have to return 0, and a recursive one (we're at some positive integer) so have to add 1 to the total steps required from our next entry.
By doing this single recursive call and adding one to the result, we make it clearer what the recursion is doing.
If this is unclear, then this alternative might show what I mean:
const takeStep = (n) =>
n % 2 == 0 ? n / 2 : n - 1
const numberOfSteps = (n) =>
n <= 0
? 0
: 1 + numberOfSteps (takeStep (n))
Think you just need to return 0 when it's...zero.
var numberOfSteps = function(num) {
if (num == 0) {
return 0;
} else {
if (num % 2 == 0) {
return 1 + numberOfSteps(num/2);
} else {
return 1 + numberOfSteps(num - 1);
}
}
}
return + 1 maybe doesn't do what you think it does: it returns the number 1. + here means positive not negative, there is no addition or subtraction going on. It will also give you one too many steps.
return; by itself returns undefined, which when converted to a Number, translates to NaN, because, well, it's not a number.
I'm reading a JavaScript book, I'm new at this, so I got to the part of recursion and I get how recursion works but is not that part is hard to me is the math part.
This is the code:
function isEven(n) {
if (n == 0)
return true;
else if (n == 1)
return false;
else if (n < 0)
return isEven(-n);
else
return isEven(n - 2);
}
lets say I pass to the function 50 as a value right
isEven(50);
That give me true... how come 50 == 0 is true or 75 == 1 is false... I really don't get it.
When you pass 50 to this function, it goes to the last block (else) and is executed recursively. When you write return isEven(n - 2);, you execute isEven(48), and then the next time isEven(46) and so on right upto the point where you reach isEven(0).
This calls the first if block and you get true as your output. The true is returned by isEven(0), followed by isEven(2) (becuase when you executed isEven(2) you ended up going to return isEven(0)) and this bubbles up the stack to finally return the output of isEven(50) as true.
This code is kind of a long way of checking whether a number is even. It relies on the fact that if a number is even and you continually subtract 2 from it, you'll eventually reach 0. Otherwise, if your number is odd, subtracting 2 repeatedly will eventually reach 1.
So if the number you pass is greater than 0, it will send the next number (n - 2) back to the function again, until it either reaches 0 or 1. Then we stop.
If the number is negative, we just flip the sign and do the same process.
This is an interesting way of applying recursion to an issue that could be solved as simply as:
return n % 2 == 0
Basically, it works by having two base cases: n == 0 and n == 1. Both of these are "known", so they just return true or false. If the number is negative, do a recursive call with the sign reversed (isEven(-n)). Otherwise, you just subtract 2 (isEven(n - 2)). This works because any odd number minus 2 is still an odd number, and even number minus 2 is still even. So, you simply keep subtracting 2 from n until n fits one of the base cases (n == 0 or n == 1).
if (n == 0) // base case
return true;
else if (n == 1) // base case
return false;
else if (n < 0) // reverse sign, call recursively
return isEven(-n);
else // default, subtracts 2, calls recursively
return isEven(n - 2);
Use this tool to visualize your code and you'll see where you're getting hung up.
Click the Forward > button after the page loads to step through your code.
You can simplify the function by using % operator
let isEven = n => !(n % 2);