Again, I'm still working with recursion, I've got a question regarding one of the base cases.
UPD: a and b represent the 1st numbers in the sequence and n is the desired position for the to-be calculated sum.
My code is as follows:
public static int fib(int a, int b, int n) {
if (n <=1) {
return a;
} else if (n == 2) {
return b;
} else {
return (fib(a, b, n - 1) + fib(a, b, n - 2));
}
}
In Line 2, before i started tracing out the program by hand, i kept it as "n<=0" . However, I got a diff answer as i traced and run the program. The problem was at some point n will = to 1. So I changed the first base case to n<=1 and got same answers.
Now the question is, suppose I called the method as follows: fib(2,3,6)
the answer should be = 21 ( with line 2 = " n<=1")
but when line 2 was "n<=0" the answer was 27.
I would like to know what happens to the program when n eventually = 1 given "n<=0" in Line 2
The call when n is 1 will generate two extra recursive calls with n as 0 and n as -1. These two recursive calls will add a twice to the correct answer.
To get the nth Fibonacci, simply pass n to the function.
Assuming the sequence is 0, 1, 1, 2, 3 ...
Your algorithm will be
if n = 1 return 0
else if n = 2 return 1
else return fib(n - 2) + fib(n - 1)
I actually answered my own question.
You see at some point n = 3,
So the value to be returned will eventually lead to n =1 as follows:
return (Fib(2,3,2)+ Fib(2,3,1))
Now that n = 1 the base case in Line 2 will be executed properly.
whereas if the base case in Line 2 was " n<=0" then for the case of n =3
return (Fib(2,3,2) + Fib(2,3,1))
then Fib(2,3,1) will cause the method to be called again and will result to n =0 and that will lead to having n = -1 & n =-2 causing the answers to differ.
//UpDATED: having n =0 & n=-1 will cause the answers to differ
You have two base cases where both will hit eventually and instead of returning n which would be correct it returns one of the passed and unchanged variables a or b.
Your code is a messy combination of the two different ways of computing the fibonacci series.
You have the recursive one that is very inefficient:
public static int fib(int n) {
if (n <=1)
return n;
return fib(n-1) + fib(n-2);
}
But, as you see it will compute everything severeal times. If you see the sequence you can iterate from the beginning by having two numbers, a and b, as arguments:
a 0 1 1 2 3 5 ...
b 1 1 2 3 5 8 ...
To compute the next a, you use b. To compute the new a you add a and b. Thus a more efficient algorithm is:
public static int fib(int a, int b, int n) {
if (n <= 0)
return a;
return fib(b, a+b, n-1);
}
Java does not tail call optimize so recursion won't work as well as in other languages that does optimize tail calls, thus an non recursive version of this would be better, like:
public static int fib(int n) {
for(int a=0, b=1;; n--) {
if (n <= 0)
return a;
int tmpa = a;
a = b;
b += tmpa;
}
}
Related
I am trying to understand why the below functions are outputting zero for any input I give them. I would have thought that based on the recursive nature that inputting a 2 to function g, would produce 12. Any integer I seem to use for either function simply outputs 0. Can anyone point to where I am going wrong in my thought process?
public class dsdsfsd {
public static int i(int n) {
if (n == 0) return 0;
return i(n-1) + g(n-1);
}
public static int g(int n) {
if (n == 0) return 0;
return g(n-1) + i(n);
}
public static void main(String[] args) {
int a = 2;
System.out.println(g(a));
System.out.println(i(a));
System.out.println(g(g(a)));
}
}
Sure. The only value these functions can return is 0. That's the base case, and the higher cases do nothing but add up those zeroes. Where do you see another value entering the equation?
If either function has zero as an argument, it returns 0.
If it has any other value, it returns the sum of two recursive calls.
The sum of two zeros is zero.
Where exactly do you expect the function to produce anything but zero?
Your problem is not on the recurrence but on the initialization of your variables.
I reckon that you try to calculate some linked coefficients by the formulas:
g(n) = g(n-1) + i(n)
i(n) = i(n-1) + g(n-1)
g(0) = 0
i(0) = 0
However, as you initialized g and i to 0, i(1) = g(0) + i(0) = 0 + 0 = 0, and any values of g(n) or i(n) will be 0 for the same reason which is: you keep adding 0's and 0's.
Instead if you want to have a non-null result you should change at least one of your initialization, for example:
g(0) = 1
i(0) = 1
That way, you have i(1) = g(0) + i(0) = 1 + 1 = 2 and g(1) = g(0) + i(1) = 1 + 2 = 3.
This is more a mathematical issue in the end.
You could reduce this to a single function for simplicity, since the mutual recursion is irrelevant:
public static int func(int n) {
if (n == 0) return 0;
return func(n-1);
}
Notice there are only 2 ways for this to return:
It can return 0 directly in the base case
It can return the result of recursing.
Think about that. At some point, it must stop recursing (or else it will run forever). What happens when the base case of 0 is returned? Your function turns into something like this (for imagining purposes only of course):
public static int func(int n) {
if (n == 0) return 0;
return 0;
}
Therefore, 0 is the only value your function(s) are capable of returning, since it's the only concrete value ever returned.
as a beginner in programming I am trying to convert the following recursive method to an iterative one but I just don't get the hang of it. The method or function has a binary tree like recursion and I would like to use an array for the iterative solution.. unfortunately I am very confused how to do it.
I have already checked the way of converting the fibonnaci recursive method to an iterative one. But I think this is not the same here. Also I am not sure if a tree search method is useful?! Any help, hint, idea would be appreciated. Thanks.
public static int funct(int n) {
if (n == 0) return 1;
if (n == 1) return 2;
if n > 1 return funct(n-2)*funct(n/2);
}
Since every n-th member is computed by others before if you can cache all in a list. You start by adding the first 2 known members. Fibonacci its easier because you always need only previous value.
private static int func(int n) {
List<Integer> values = new ArrayList<>(n+1);
values.add(1);
values.add(2);
for (int i = 2; i <= n; i++) {
values.add(values.get(i - 2) * values.get(i / 2));
}
return values.get(n);
}
Now the real function is without last if:
public static int funct(int n) {
if (n == 0) return 1;
if (n == 1) return 2;
return funct(n-2) * funct(n/2);
}
As the recursive calls refer to smaller parameters one can cache all return values upto n.
Unfortunately this already spoils the pleasure, as the resulting code is complete:
public static int funct(int n) {
int[] results = new int[n+1];
results[0] = 1;
results[1] = 2;
int i = 2;
while (i <= n) {
results[i] = results[i-2] * results[i/2];
++i;
}
return results[n];
}
It indeed looks like fibonacci.
In general one would not need to fill all items of results. like probably results[n - 1].
Unfortunately you should have learnt prior to this problem:
Solving tail recursion.
Using a stack (like here) to use inner results of a recurive call.
You might look into those topics.
Math afterlude
The initial values are powers of 2. As the result is a product of earlier results, all results will be powers of 2.
f(0) = 1 = 2^0
f(1) = 2 = 2^1
f(n) = f(n - 2) * f(n / 2)
Hence you can introduce:
g(0) = 0
g(1) = 1
g(n) = g(n - 2) + g(n / 2)
f(n) = 2^g(n)
This will enlarge the range you can calculate as say 2100.
You will also see:
g(2k + 1) = g(2k) + 1
So you will only need a domain of even numbers:
g(2k) = g(2(k-1)) + g(k - k%2) + k%2
Basically what I wanted to is if a number n is divisible by b for a(count) times, then find the a(count), and divide n by b for a(count) times.
That is,
count = 0;
while(n%b == 0)
n=n/b;
count = count + 1;
How to optimize this, so that everything can be obtained in one step
You can do it in O(log(a)) by applying binary search, on a sorted "list" to find the last element that equals 1.
The list is metaphoric, and each element in it is calculated on the fly when queried by a simple calculation:
list[i] = 1 n % a^i == 0
0 otherwise
You can first find the range of possible a's using exponention:
curr = b
tempA = 1
while n % curr == 0:
curr = curr * curr
tempA = tempA *2
And then, run the binary search on the range [tempA/2, tempA]. This range is of size (a/2), so finding the last "element" that the symbolic list holds 1 - is done in O(loga) multiplications.
Code + Demo:
private static int specialBinarySearch(int n, int b, int aLow, int aHigh) {
if (aHigh == aLow) return aHigh;
int mid = (aHigh - aLow)/2 + aLow;
//pow method can be optimized to remember pre-calculated values and use them
int curr = (int)Math.round(Math.pow(b, mid));
if (n % curr == 0) { //2nd half, or found it:
if (n % (curr*b) != 0) return mid; //found it
return specialBinarySearch(n, b, mid+1, aHigh); //2nd half
}
else return specialBinarySearch(n, b, aLow, mid); //first half
}
public static int findA(int n, int b) {
int curr = b;
int tempA = 1;
while (n % curr == 0) {
curr = curr * curr;
tempA = tempA *2;
}
return specialBinarySearch(n, b, tempA/2, tempA);
}
public static void main(String args[]) {
System.out.println(findA(62,2)); //1
System.out.println(findA(1024,2)); //10
System.out.println(findA(1,2)); //0
System.out.println(findA(100,2)); //2
System.out.println(findA(6804,3)); //5
}
You cannot solve this in O(1) but there is a different kind of approach to this problem if you start using a numeric system where b is the base.
For example, if we have a number like 154200, and b is 10, we know the answer is 2 here immediately because we can simply count how many zeros there are on the right hand side.
Similarly, in binary, if b is 2, you simply count how many zeros there are on the right side with a binary representation.
If b is 5, we have to use the odd base 5 representation where a number like 8 is represented as 13. Again we know that the answer for a is zero is n=8 and b=5 because there are no zeros on the right hand side.
This won't necessarily give you speed gains except possibly in cases where b is a power of two where you can use bitwise logic to deduce the answer, but it gives you a different kind of way of looking at the problem lexically by digits instead of through arithmetic.
this is a java code that recursively counts the number of payments in specific coins (ex. 1, 2, 5, 20, 50 etc.). I have tried to figure out how it works but can't seem to get it. Could somebody please be so kind and explain the math and logic behind the code and how this recursion works? I would really appreciate it.
// Returns the count of ways we can sum S[0...m-1] coins to get sum n
int count( int S[], int m, int n ){
// If n is 0 then there is 1 solution (do not include any coin)
if (n == 0)
return 1;
// If n is less than 0 then no solution exists
if (n < 0)
return 0;
// If there are no coins and n is greater than 0, then no solution exist
if (m <=0 && n >= 1)
return 0;
// count is sum of solutions (i) including S[m-1] (ii) excluding S[m-1]
return count( S, m - 1, n ) + count( S, m, n-S[m-1] );
}
The method works like this:
First statements are the stopping conditions for the current recursion (without these for all cases then you end up with an infinite loop which ultimately end in a StackOverFlow)
The final line is where the calculation occurs. Each of the statements is reducing the problem into smaller chunks by:
count( S, m - 1, n ) reduces the number of coins (m-1) which excludes the last coin in the next recursive call to
count( S, m, n-S[m-1]) uses the last coin in the array and reduces the sum that is need to reach by the value of that coin
Consider this small example:
S[] = {1,2) // We have a 1 and 2 cent coin
m = S.length // Consider all possibilities ( = 2)
n = 3 // How many ways can we make 3c
// Obviously with: 1x1c + 1x2c
// and: 3x1c
The recursion as a tree; left branch = count( S, m - 1, n ), right branch = count( S, m, n-S[m-1]):
m=2;n=3
/ \
m=1;n=3 m=2;n=1
/ \ / \
m=0;n=3 m=1;n=2 m=1;n=1 m=2;n=-1
/ \ / \
m=0;n=2 m=1;n=1 m=0;n=1 m=1;n=0
/ \
m=0;n=1 m=1;n=0
This recursion can be thought of as a Pre-order Traversal of this tree.
If you then consider the conditions of the method for where a solution is found or not. So at the leaf nodes where n = 0.
Each which comes about like this:
First solution
m=1;n=3 - Exclude the last coin (2c)
m=1;n=2 - Use this coin (1c) and reduce by 1
m=1;n=1 - Use this coin (1c) and reduce by 1
m=1;n=0 - Use this coin (1c) and reduce by 1
n = 0 - a solution (3x1c)
Second Solution
m=2;n=1 - Use this coin(2c) and reduce by 2
m=1;n=1 - Exclude the last coin (2c)
m=1;n=0 - Use this coin (1c) and reduce by 1
n = 0 - a solution (1x2c + 1x2c)
At each node a value is returned - 0 (no solution) or 1 (a solution) - to add to the total count of solutions found. Once the recursion ends this final value is returned and is the number of solutions.
Some additional notes:
This piece of code will only consider the first m coins in the array S so to consider all the possible ways the initial call to the method needs to have m == S.length
Assumes that each coin can be used multiple times
Code modification with print statements to see the recursion:
public static void main(String[] args){
int[] coins = new int[]{1,2};
System.out.println("Final Count = " + count(coins, coins.length, 3, ""));
}
public static int calls = 0;
public static int count( int S[], int m, int n , String from){
calls++;
System.out.print("Call#" + calls + ": " + from + "; m = " + m + "; n = " + n);
// If n is 0 then there is 1 solution (do not include any coin)
if (n == 0)
{
System.out.println(" - Solution Found");
return 1;
}
// If n is less than 0 then no solution exists
if (n < 0)
{
System.out.println(" - No Solution Found n < 0");
return 0;
}
// If there are no coins and n is greater than 0, then no solution exist
if (m <=0 && n >= 1)
{
System.out.println(" - No Solution Found (other Case)");
return 0;
}
System.out.println();
// count is sum of solutions (i) including S[m-1] (ii) excluding S[m-1]
return count( S, m - 1, n , from + "E" ) + count( S, m, n-S[m-1], from + "I" );
}
From the code, I'm assuming S is an array with at least m elements, with each element representing an available coin denomination, and n is the intended sum.
The comments really say it all, except that the last comment is backwards. count( S, m - 1, n ) is the number of solutions excluding the last coin in the current range. count( S, m, n-S[m-1] ) is the number of solutions using that coin.
The exclude case simply drops the last coin in the current range by reducing m by one.
The include case uses it by reducing n by that coin's value. Since the include case does not also reduce m, presumably any coin denomination can be used multiple times. It does not matter if the coin is too big - that is taken care of by returning 0 if n < 0.
If anything about the base cases is not clear from the comments, please ask a specific question.
I'm studying the code below in my textbook. It uses the combinations method and the factorial method to calculate the possible outcomes given n and k. My question is with the factorial method specifically the content in the for loop.
I understand everything else about the program but I don't understand the code i <=n in the for loop in the factorial method. What other part of the program is n referred to? I'm just not sure about the rationale behind i <= n or how the programmer comes up with that.
import acm.program.*;
public class combinations extends ConsoleProgram {
public void run(){
int n = readInt("Enter the number of objects in the set (n): ");
int k = readInt("Enter the number to be chosen (k): ");
println("C (" + n + ", " + k + ") = " + combinations (n, k) );
}
private int combinations (int n, int k){
return factorial (n) / (factorial (k) * factorial (n-k));
}
private int factorial (int n){
int result = 1;
for (int i = 1; i <= n; i++){
result *= i;
}
return result;
}
}
n is a parameter of the method: because the method is declared as int factorial(int n), you invoke it as (for example) factorial(5) to get the local variable n set to 5. (In formal terms, n is the parameter and 5 is the argument, though usually people don't bother to distinguish those two terms.)
So, a bit of math. Typically, when one deals with a mathematical expression, math conventions are frequently used. n is typically referred to some upper ceiling value that the method should refer to.
Essentially, the function definition for a factorial is this.
factorial(n) = { 1 if n = 0, n*factorial(n-1) otherwise.
The loop includes the final value of n, so you get the full expression of the function (if you didn't, your answer would be off by a factor of n every time.
You need i <= n because when you calculate factorial of 3! for example, you will have
3! = 3 * 2 * 1 <=> 1 * 2 * 3
So, you have your n, that is 3 and the i is 1, then 2, then 3 (n).
If you look closely you see that in loop for i take a values from 1 to n, so in i=n point for loop terminated. Loop for is created in this form to assure that factorial(0)=1. However, you can redesign this function in recursive style.