Recursion on staircase - recursion

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

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.

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.

Sum of roots of binary search trees of height ≤H with N nodes

Consider all Binary Search Trees of height ≤H that can be created using the first N natural numbers. Find the sum of the roots of those Binary Search Trees.
For example, for N = 3, H = 3: There are 2 trees with 1 as root, 1 tree with 2 as root and 2 trees with 3 as root.
Hence, Sum = 2∗(1)+1∗(2)+2∗(3)=10
I am trying to solve this problem by writing a function f(n,h) which is related to f(n−1,h−1) and f(n−1,h) in some way, but unable to find the solution.
Note: All numbers [1,N] must be present in the tree and the height should be ≤H
Ok let us start with basics.
The number of BST that can be created using first N natural numbers can be very easily calculated using the following algorithm.
natural_number compute_no_of_BST(N)
{
if(N<=1)
return 1;
else
{
left=0,right=0,sum=0;
for(root = 1 to N)
{
left = compute_no_of_BST(root-1);
right = compute_no_of_BST(N-root);
sum = sum + (left*right);
}
return sum;
}
}
Explanation:
The key to understand this algorithm is this:
No matter what the distinct keys are, the number of BST only depends on number of distinct keys
So, this is what we use in recursion.For the left subtree number of distinct values are root-1 and for the right subtree the number of distinct values are N-root.Also we give every key the chance of being the root using the for loop.
Now, let us handle the constraint of height H.I am assuming the height to be the number of edges from root to leaf path. This can also be handled by focusing on the above algorithm and the trick is:
We will not call the recursive function calls for height > H and for this we must keep track of the number of edges traversed from root, which initially is 0.
So that kind of narrows it down to what are new function call will look like.
natural_number compute_no_of_BST(N,H,0);
And every time we make a recursive call, we increment the third variable to indicate an edge traversal.
We will also use an extra data structure, which is an array of length N where
arr[i] = number of BST with root i+1.
Here goes the algorithm for this
natural_number compute_no_of_BST(N,H,l)
{
if(N<=1)
return 1;
else
{
left=0,right=0,sum=0;
for(root = 1 to N)
{
if(l+1<=H)
{
left = compute_no_of_BST(root-1,H,l+1);
right = compute_no_of_BST(N-root,H,l+1);
if(l==0)
arr[root-1] = (left*right);
sum = sum + (left*right);
}
}
return sum;
}
}
Now sum can be easily computed as
arr[0]*1 + arr[1]*2 + ..... arr[N-1]*N.
Here is just a DP conversion of the above recursive algorithm.
int bottom_up_specific_height(int n,int h){
int i,j,l;
for(l=0;l<=h;l++){
dp[0][l]=1;
dp[1][l]=1;
}
int s=0;
for(i=2;i<=n;i++){
for(j=1;j<=i;j++){
for(l=h;l>=0;l--){
if(l==h)
dp[i][l]=0;
else
dp[i][l]+=(dp[j-1][l+1]*dp[i-j][l+1]);
if(l==0 && i==n)
s+=(j)*(dp[j-1][l+1]*dp[i-j][l+1]);
}
}
}
return s;
}
Here complexity reduces to O(h*n^2).
Is it possible to optimize it further!!

Fibonacci sequence in solving an equation

Im trying to figure out an equation. This is f(n)=f(n-1) + 3n^2 - n. I also have the values to use as f(1), f(2), f(3). How would i go about solving this??
You would usually use recursion but, whether you do that or an iterative solution, you're missing (or simply haven't shown us) a vital bit of information, the terminating condition such as f(1) = 1 (for example).
With that extra piece of information, you could code up a recursive solution relatively easily, such as the following pseudo-code:
define f(n):
if n == 1:
return 1
return f(n-1) + (3 * n * n) - n
As an aside, that's not actually Fibonacci, which is the specific 1, 1, 2, 3, 5, 8, 13, ... sequence.
It can be said to be Fibonacci-like but it's actually more efficient to do this one recursively since it only involves one self-referential call per level whereas Fibonacci needs two:
define f(n):
if n <= 2:
return 1
return f(n-2) + f(n-1)
And if you're one of those paranoid types who doesn't like recursion (and I'll admit freely it can have its problems in the real world of limited stack depths), you could opt for the iterative version.
define f(n):
if n == 1:
return 1
parent = 1
for num = 2 to n inclusive:
result = parent + (3 * num * num) - num
parent = result
return result
If you ask this question on a programming site such as Stack Overflow, you can expect to get code as an answer.
On the other hand, if you are looking for a closed formula for f(n), then you should direct your question to a specialised StackExchange site such as Computer Science.
Note: what you are looking for is called the repertoire method. It can be used to solve your problem (the closed formula is very simple).

How do I use Master theorem to describe recursion?

Recently I have been studying recursion; how to write it, analyze it, etc. I have thought for a while that recurrence and recursion were the same thing, but some problems on recent homework assignments and quizzes have me thinking there are slight differences, that 'recurrence' is the way to describe a recursive program or function.
This has all been very Greek to me until recently, when I realized that there is something called the 'master theorem' used to write the 'recurrence' for problems or programs. I've been reading through the wikipedia page, but, as usual, things are worded in such a way that I don't really understand what it's talking about. I learn much better with examples.
So, a few questions:
Lets say you are given this recurrence:
r(n) = 2*r(n-2) + r(n-1);
r(1) = r(2)
= 1
Is this, in fact, in the form of the master theorem? If so, in words, what is it saying? If you were to be trying to write a small program or a tree of recursion based on this recurrence, what would that look like? Should I just try substituting numbers in, seeing a pattern, then writing pseudocode that could recursively create that pattern, or, since this may be in the form of the master theorem, is there a more straightforward, mathematical approach?
Now, lets say you were asked to find the recurrence, T(n), for the number of additions performed by the program created from the previous recurrence. I can see that the base case would probably be T(1) = T(2) = 0, but I'm not sure where to go from there.
Basically, I am asking how to go from a given recurrence to code, and the opposite. Since this looks like the master theorem, I'm wondering if there is a straightforward and mathematical way of going about it.
EDIT: Okay, I've looked through some of my past assignments to find another example of where I'm asked, 'to find the recurrence', which is the part of this question I'm having the post trouble with.
Recurrence that describes in the best
way the number of addition operations
in the following program fragment
(when called with l == 1 and r == n)
int example(A, int l, int r) {
if (l == r)
return 2;
return (A[l] + example(A, l+1, r);
}
A few years ago, Mohamad Akra and Louay Bazzi proved a result that generalizes the Master method -- it's almost always better. You really shouldn't be using the Master Theorem anymore...
See, for example, this writeup: http://courses.csail.mit.edu/6.046/spring04/handouts/akrabazzi.pdf
Basically, get your recurrence to look like equation 1 in the paper, pick off the coefficients, and integrate the expression in Theorem 1.
Zachary:
Lets say you are given this
recurrence:
r(n) = 2*r(n-2) + r(n-1); r(1) = r(2)
= 1
Is this, in fact, in the form of the
master theorem? If so, in words, what
is it saying?
I think that what your recurrence relation is saying is that for function of "r" with "n" as its parameter (representing the total number of data sets you're inputting), whatever you get at the nth position of the data-set is the output of the n-1 th position plus twice whatever is the result of the n-2 th position, with no non-recursive work being done. When you try to solve a recurrence relation, you're trying to go about expressing it in a way that doesn't involve recursion.
However, I don't think that that is in the correct form for the Master Theorem Method. Your statement is a "second order linear recurrence relation with constant coefficients". Apparently, according to my old Discrete Math textbook, that's the form you need to have in order to solve the recurrence relation.
Here's the form that they give:
r(n) = a*r(n-1) + b*r(n-2) + f(n)
For 'a' and 'b' are some constants and f(n) is some function of n. In your statement, a = 1, b = 2, and f(n) = 0. Whenever, f(n) is equal to zero the recurrence relation is known as "homogenous". So, your expression is homogenous.
I don't think that you can solve a homogenous recurrence relation using the Master Method Theoerm because f(n) = 0. None of the cases for Master Method Theorem allow for that because n-to-the-power-of-anything can't equal zero. I could be wrong, because I'm not really an expert at this but I don't that it's possible to solve a homogenous recurrence relation using the Master Method.
I that that the way to solve a homogeneous recurrence relation is to go by 5 steps:
1) Form the characteristic equation, which is something of the form of:
x^k - c[1]*x^k-1 - c[2]*x^k-2 - ... - c[k-1]*x - c[k] = 0
If you've only got 2 recursive instances in your homogeneous recurrence relation then you only need to change your equation into the Quadratic Equation where
x^2 - a*x - b = 0
This is because a recurrence relation of the form of
r(n) = a*r(n-1) + b*r(n-2)
Can be re-written as
r(n) - a*r(n-1) - b*r(n-2) = 0
2) After your recurrence relation is rewritten as a characteristic equation, next find the roots (x[1] and x[2]) of the characteristic equation.
3) With your roots, your solution will now be one of the two forms:
if x[1]!=x[2]
c[1]*x[1]^n + c[2]*x[2]^n
else
c[1]*x[1]^n + n*c[2]*x[2]^n
for when n>2.
4) With the new form of your recursive solution, you use the initial conditions (r(1) and r(2)) to find c[1] and c[2]
Going with your example here's what we get:
1)
r(n) = 1*r(n-1) + 2*r(n-2)
=> x^2 - x - 2 = 0
2) Solving for x
x = (-1 +- sqrt(-1^2 - 4(1)(-2)))/2(1)
x[1] = ((-1 + 3)/2) = 1
x[2] = ((-1 - 3)/2) = -2
3) Since x[1] != x[2], your solution has the form:
c[1](x[1])^n + c[2](x[2])^n
4) Now, use your initial conditions to find the two constants c[1] and c[2]:
c[1](1)^1 + c[2](-2)^1 = 1
c[1](1)^2 + c[2](-2)^2 = 1
Honestly, I'm not sure what your constants are in this situation, I stopped at this point. I guess you'd have to plug in numbers until you'd somehow got a value for both c[1] and c[2] which would both satisfy those two expressions. Either that or perform row reduction on a matrix C where C equals:
[ 1 1 | 1 ]
[ 1 2 | 1 ]
Zachary:
Recurrence that describes in the best
way the number of addition operations
in the following program fragment
(when called with l == 1 and r == n)
int example(A, int l, int r) {
if (l == r)
return 2;
return (A[l] + example(A, l+1, r);
}
Here's the time complexity values for your given code for when r>l:
int example(A, int l, int r) { => T(r) = 0
if (l == r) => T(r) = 1
return 2; => T(r) = 1
return (A[l] + example(A, l+1, r); => T(r) = 1 + T(r-(l+1))
}
Total: T(r) = 3 + T(r-(l+1))
Else, when r==l then T(r) = 2, because the if-statement and the return both require 1 step per execution.
Your method, written in code using a recursive function, would look like this:
function r(int n)
{
if (n == 2) return 1;
if (n == 1) return 1;
return 2 * r(n-2) + r(n-1); // I guess we're assuming n > 2
}
I'm not sure what "recurrence" is, but a recursive function is simply one that calls itself.
Recursive functions need an escape clause (some non-recursive case - for example, "if n==1 return 1") to prevent a Stack Overflow error (i.e., the function gets called so much that the interpreter runs out of memory or other resources)
A simple program that would implement that would look like:
public int r(int input) {
if (input == 1 || input == 2) {
return 1;
} else {
return 2 * r(input - 2) + r(input -1)
}
}
You would also need to make sure that the input is not going to cause an infinite recursion, for example, if the input at the beginning was less than 1. If this is not a valid case, then return an error, if it is valid, then return the appropriate value.
"I'm not exactly sure what 'recurrence' is either"
The definition of a "recurrence relation" is a sequence of numbers "whose domain is some infinite set of integers and whose range is a set of real numbers." With the additional condition that that the function describing this sequence "defines one member of the sequence in terms of a previous one."
And, the objective behind solving them, I think, is to go from a recursive definition to one that isn't. Say if you had T(0) = 2 and T(n) = 2 + T(n-1) for all n>0, you'd have to go from the expression "T(n) = 2 + T(n-1)" to one like "2n+2".
sources:
1) "Discrete Mathematics with Graph Theory - Second Edition", by Edgar G. Goodair and Michael M. Parmenter
2) "Computer Algorithms C++," by Ellis Horowitz, Sartaj Sahni, and Sanguthevar Rajasekaran.

Resources