What is the Space Complexity of following function and how? - recursion

Consider following recursive function.
int f(int n){
if(n<=0) return 1; return f(n-1)+f(n-1);
}
It is said that though there are 2^N (2 powered to N) calls but only N calls exist at a given time. Can someone explain how?

Sure. The complexity part is in the else portion:
return f(n-1)+f(n-1)
This spawns two calls at n-1 for each call at n. However, note the order of evaluation:
call f(n-1) ... left side
save the value as temp1
call f(n-1) ... right side
add the value to temp1
return that value
The entire left-side call tree has to complete before the right-side call tree can begin -- and that happens at every depth level. For each value of n, there will be only one call active at any point in time. For instance, f(2) gives us a sequence like this:
call f(2)
n isn't <= 0 ...
call f(1) ... left
n isn't <= 0 ...
call f(0) ... left | left
n <= 0; return 1
save the 1
call f(0) ... left | right
n <=0; return 1
add the 1 to the temp value;
return 2
save the 2
call f(1) ... right
call f(0) ... left | left
n <= 0; return 1
save the 1
call f(0) ... left | right
n <=0; return 1
add the 1 to the temp value;
return 2
add this 2 to the temp value, making 4
return the 4
done ...
At each point, there are no more than n+1 calls active (see indentation level), although we eventually execute 2^(n+1)-1 calls. We're off by one (n+1 instead of n) because we terminate at 0 instead of 1.
Does that clear things up?

For each n, f(n-1) is called twice. So if you draw a tree with n at root and add a branch for each call to f(n-1) and so on, you will see that you have a full binary tree of height n, which has 2^n nodes (total number of calls).
But it is important to note that the second call to f(n-1) cannot be initiated without first completing the first call and returning the result. The same holds recursively for f(n-2) calls inside f(n-1), ... .
The worst case (I assume that is what you are looking for), happens when the set of your function calls reach f(0) and you are at one of the leaves of the call tree. What you have in your call stack is a set of function calls starting from f(n-1), f(n-2), ... , f(1), f(0). So at each point of time you have at most O(n) functions in your stack. (Which is equal to the height of the call tree).

Related

In SML - Why doesn't simple recursion always return 0 if first expression met?

In a simple recursion with first if expression true then 0. if steps in the recursion keeps going until that first expression is true, why isn't 0 always returned?
fun stepping (n : int, number : int) =
if number > n
then 0
else 1 + stepping (n, number + 1)
It seems like the function stepping should add one onto number until number > n and then always return 0. Instead, it returns the number of times you went through the recursion cycle until number becomes greater than n.
The above code tests good in SML and gave me what I wanted - the number of steps incrementing by 1 until input "number" is greater than the input "n". But manually walking through the recursion steps, it seems like the return should always be 0 when the incremented "number" > the input "n". What am I missing?
I think you're mistaking the result of the final call to stepping in the recursive chain (which will always be zero) as being the ultimate value returned by the expression, but that is not the case. It is actually part of a larger equation that makes up the overall returned value.
For example, if we look at how the expression gets built up as each recursive call is made when evaluating stepping(3, 1), you end up with...
result = stepping(3, 1)
result = 1 + stepping(3, 2)
result = 1 + 1 + stepping(3, 3)
result = 1 + 1 + 1 + stepping(3, 4)
result = 1 + 1 + 1 + 0
result = 3
Let's say that I'm going to give you some money this year, according to this scheme:
you get nothing on the first of January
on all other days, you get one dollar more than I would have given you the day before
How much would I have to pay you today, the 20th of February?
Fifty dollars or nothing at all?
If you follow the calendar backwards, you will eventually reach January 1st, where the payment is zero, so would you expect to get nothing?
To answer your immediate question: the function does always return 0 if the first condition is met – that is, if number > n.
However, if the first condition isn't met – number <= n – it does not return 0 but 1 + stepping (n, number + 1).
It works exactly like of you called a function with a different name; that function computes a value and then this function adds 1.
It's not like returning a value from inside a loop, such as (pseudocode)
while (true)
{
if number > n
return 0
else
number = number +1
}
which is perhaps what you're thinking about.

Generating an item from an ordered sequence of exponentials

I am writing a solution for the following problem.
A is a list containing all elements 2^I * 3^Q where I and Q are integers in an ascending order.
Write a function f such that:
f(N) returns A[N]
The first few elements are:
A[0] = 1
A[1] = 2
A[2] = 3
A[3] = 4
A[4] = 6
A[5] = 8
A[6] = 9
A[7] = 12
My solution was to generate a list containing the first 225 elements by double looping in 15 times each, then sorted this list and return A[N]
Is there any way to generate the N'th element of this sequence without creating and sorting a list first?
Here are two approaches that solve your problem without creating such a large list. Each approach has its disadvantages.
First, you could set a counter to 0. Then scan all the integers from 1 on up. For each integer, divide out all the multiples of 2 and of 3 in its factorization. If 1 remains, increment the counter; otherwise, leave the counter unchanged. When the counter reaches N you have found the value of A[N]. For example, you increase the counter for integers 1, 2, 3, and 4, but not for 5. This approach uses very little memory but would take much time.
A second approach uses a min priority queue, such as Python's heapq. Again, set a counter to zero, but also initialize the priority queue to hold only the number 1 and note that the highest power of 3 seen so far is also 1. Increment the counter then peek at the minimum number in the queue. If the counter is N you just got your value of A[N]. Otherwise, pop that min value and immediately push double its value. (The pop and push can be done in one operation in many priority queues.) If that value was a the highest power of 3 seen so far, also push three times its value and note that this new value is now the highest power of 3.
This second approach uses a priority queue that takes some memory but the largest size will only be on the order of the square root of N. I would expect the time to be roughly equal to your sorting the large list, but I am not sure. This approach has the most complicated code and requires you to have a min priority queue.
Your algorithm has the advantage of simplicity and the disadvantage of a large list. In fact, given N it is not at all obvious the maximum powers of 2 and of 3 are, so you would be required to make the list much larger than needed. For example, your case of calculating "the first 225 elements by double looping in 15 times each" actually only works up to N=82.
Below I have Python code for all three approaches. Using timeit for N=200 I got these timings:
1.19 ms for sorting a long list (your approach) (powerof2=powerof3=30)
8.44 s for factoring increasing integers
88 µs for the min priority queue (maximum size of the queue was 17)
The priority queue wins by a large margin--much larger than I expected. Here is the Python 3.6.4 code for all three approaches:
"""A is a list containing all elements 2^I * 3^Q where I and Q are
integers in an ascending order. Write a function f such that
f(N) returns A[N].
Do this without actually building the list A.
Based on the question <https://stackoverflow.com/questions/49615681/
generating-an-item-from-an-ordered-sequence-of-exponentials>
"""
import heapq # min priority queue
def ordered_exponential_0(N, powerof2, powerof3):
"""Return the Nth (zero-based) product of powers of 2 and 3.
This uses the questioner's algorithm
"""
A = [2**p2 * 3**p3 for p2 in range(powerof2) for p3 in range(powerof3)]
A.sort()
return A[N]
def ordered_exponential_1(N):
"""Return the Nth (zero-based) product of powers of 2 and 3.
This uses the algorithm of factoring increasing integers.
"""
i = 0
result = 1
while i < N:
result += 1
num = result
while num % 2 == 0:
num //= 2
while num % 3 == 0:
num //= 3
if num == 1:
i += 1
return result
def ordered_exponential_2(N):
"""Return the Nth (zero-based) product of powers of 2 and 3.
This uses the algorithm using a priority queue.
"""
i = 0
powerproducts = [1] # initialize min priority queue to only 1
highestpowerof3 = 1
while i < N:
powerproduct = powerproducts[0] # next product of powers of 2 & 3
heapq.heapreplace(powerproducts, 2 * powerproduct)
if powerproduct == highestpowerof3:
highestpowerof3 *= 3
heapq.heappush(powerproducts, highestpowerof3)
i += 1
return powerproducts[0]

How many times does this recursive function iterate?

I have a recursive function, as follows, where b >= 0
def multiply(a,b):
if b == 0:
return 0
elif b % 2 == 0:
return multiply(2*a, b/2)
else:
return a + multiply(a, b-1)
I would like to know how many times the function will run in terms of a and b.
Thanks.
If binary representation of b (call it B) ends with 1, like xxxx1 than next call to multiply has B = xxxx0.
If B ends with 0, like xxxx0 than next value of B is xxxx.
With that, digit of binary representation of b adds one call if it is 0, and two calls if it is 1. Summing that total number of calls equals to length of initial B + number of ones in initial B.
I might be wrong here, but I think your function does not work the way you intend it. In recursion the most important thing as a propper ending criteria, since it will run forever elseways.
Now your ending criteria is a==0, but with each recursive call you do not decrease a. Just make a pen & paper simulation with a=5 and check if it would stop at any point.

Explain the recursion in this algorithm?

I know this algorithm is for finding the majority element of any array if it has any. Can any one please explain the recursion calls?
if length(A) = 0 then
return null
end if
if length(A) = 1 then
return 1
end if
// "Command 7"
Call FIND-MAJORITY recursively on the first half of A, and let i be the result.
// "Command 8"
Call FIND-MAJORITY recursively on the second half of A, and let j be the result.
if i > 0 then
compare i to all objects in A(including itself);
let k be the number of times that equality holds;
if k > length(A)/2 then
return i.
end if
end if
if j > 0 then
compare j to all objects in A(including itself);
let k be the number of times that equality holds;
if k > length(A)/2 then
return j
end if
end if
return null
Is command 7 is executed until it get an single value ... and then command 8? I cannot understand these recursions. Please explain with example, thanks.
It depends what are inputs of this function.
If the array A is an input then we only search in the diminished array else if the array A is defined as global then you always search the whole array.
For example take the array A is 1,2,1,3,1,8,7,1
If the array is given as input to the function :
According to recursion we get A is 1,2,1,3 -> A is 1,2 -> A is 1
This returns i := 1.
Then A is 2, this returns j:=1.
Then we compare i to all elements of A i.e 1,2.
Then we compare j to all elements of A i.e. 1,2.
We return null from this recursive call.
After this we proceed to upper recursion i.e. 1,2,1,3 and up to the first call.
If the array is global:
According to recursion we get A is 1,2,1,3 -> A is 1,2 -> A is 1
This returns i := 1.
Then A is 2, this returns j:=1.
Then we compare i to all elements of A i.e. 1,2,1,3,1,8,7,1
we return according to the conditions.
**Remember even in this case we return all recursive calls and check the whole array for every recursive call which is not what you probably want.

Recursion on staircase

I'm trying to understand the solution provided in a book to the following question:
"A child is running up a staircase with n steps and can hop either 1 step, 2 steps or 3 steps at a time. Implement a method to count how many possible ways the child can run up the stairs."
The book's solution is as follows, stemming from the fact that "the last move may be a single step hop from n - 1, a double step hop from step n - 2 or a triple step hop from step n - 3"
public static int countWaysDP(int n, int[] map) {
if (n < 0)
return 0;
else if (n == 0)
return 1;
else if (map[n] > -1)
return map[n];
else {
map[n] = countWaysDP(n - 1, map) + countWaysDP(n - 2, map) + countWaysDP(n - 3, map);
return map[n]; }
}
My confusion is:
Why should the program return 1 if the number of steps is zero? The way I think about it, if the number of steps is zero, then there are zero ways to traverse the staircase. Wouldn't a better solution be something like "if (n <= 0) return 0; else if (n == 1) return 1"?
I'm not sure I understand the rationale behind making this a static method? Google says that a static method is one that is called by the entire class, and not by an object of the class. So the book's intention seems to be something like:
.
class Staircase {
static int n;
public:
static int countWaysDP(int n, int[] map); }
instead of:
class Staircase {
int n;
public:
int countWaysDP(int n, int[] map); }
Why? What's the problem with there being multiple staircases instantiated by the class?
Thanks.
(Note: Book is Cracking the Coding Interview)
To answer your first question, it turns it is the beauty of mathematics: if there is 1 step for the staircase, there is 1 way to solve it. If there is 0 steps, there is also 1 way to solve it, which is to do nothing.
It is like, for an n-step staircase, for m times, you can either walk 1, 2, or 3 steps to finish it. So if n is 1, then m is 1, and there is 1 way. If n is 0, m is 0, and there is also 1 way -- the way of not taking any step at all.
If you write out all the ways for a 2-step staircase, it is [[1, 1], [2]], and for 1-step staircase, it is [[1]], and for 0-staircase, it is [[]], not []. The number of elements inside of the array [[]] is 1, not 0.
This will become the fibonacci series if the problem is that you can walk 1 step or 2 steps. Note that fib(0) = 1 and fib(1) = 1, and it corresponds to the same thing: when staircase is 1 step, there is 1 way to solve it. When there is 0 steps, there is 1 way to solve it, and it is by doing nothing. It turns out the number of ways to walk a 2-step staircase is fib(2) is 2 and it equals fib(1) + fib(0) = 1 + 1 = 2, and it wouldn't have worked if fib(0) were equal to 0.
Answer 2:
A Static method means the function doesn't need any information from the object.
The function just takes an input (in the parameters), processes it and returns something.
When you don't see any "this" in a function, you can set it as static.
Non-static methods usually read some properties (this-variables) and/or store values in some properties.
Answer 1:
I converted this to javascript, just to show what happens.
http://jsbin.com/linake/1/edit?html,js,output
I guess this is the point. Recursion often works opposite to what you could expect. It often returns values in the opposite order.
For 5 staircases:
First it returns n=1; then n=2, ... up to n=5;
n=5 has to wait until n=4 is ready, n=4 has to wait until n=3 is ready, ...
So here is your n=0 and n<0:
The first return of the function has n=1; that calls this
map[n] = countWaysDP(n - 1, map) + countWaysDP(n - 2, map) + countWaysDP(n - 3, map)
So that is
map[n] = countWaysDP(0, map) + countWaysDP(-1, map) + countWaysDP(-2, map)
There countWaysDP(0, map) returns 1; the other terms are meaningless, so they return 0. That's why there are these clauses for n==0 and n<0
notice, you can add
+ countWaysDP(n - 4, map)
if you want to see what happens when the child can also jump 4 cases
Also notice:
As I said in answer 2, you see this function doesn't require any object. It just processes data and returns something.
So, in your case, having this function in your class is useful because your functions are grouped (they 're not just loose functions scattered around your script), but making it static means the compiler doesn't have to carry around the memory of the object (especially the properties of the object).
I hope this makes sense. There are surely people that can give more accurate answers; I'm a bit out of my element answering this (I mostly do javascript).
To try and answer your first question, why it returns 1 instead of 0, say you're looking at a stair with 2 steps in total, the recursive call then becomes:
countWaysDP(2 - 1, map) + countWaysDP(2 - 2, map) + countWaysDP(2 - 3, map);
The second recursive call is the one where n becomes zero, that's when we have found a successful path, because from 2 steps, there's obviously a path of taking 2 steps. Now, if you write as you suggested:
n == 1: return 1
you would not accept taking two steps from the two stepped stair! What the statement means is that you only count the path if it ends with a single step!
You need to think about it has a tree with 3 possible options on each node.
If the size of the staircase is 4
we will have something like this:
(4)--1-->(3)--..(Choose a step and keep branching)...
|__2-->(2)--..(Until you get size of zero)............
|__3-->(1)--1-->(0) # <--Like this <--
At the end if you count all the leafs with size of zero you will get all the possible ways.
So you can think it like this, what if you take a step and then consider update the size of the stair like this size-step, where your steps can be (1,2,3)
Doing that you can code something like this:
choices = (1, 2, 3)
counter = 0
def test(size):
global counter
if size == 0:
counter += 1
for choice in choices:
if size - choice >= 0:
test(size - choice)
return counter

Resources