Figure out Pattern for a Recursive Function - algorithm

I have difficulty to understand a pattern for this code. I tested this function and I know for input Ack(3,2) this function circles 541 times, so it must have a pattern for solving this problem. Please help me find the pattern.
public static int Ack(int m,int n)
{
if (n < 0 || m < 0) return 0;
else if (m == 0) return n + 1;
else if (n == 0) return Ack(m - 1, 1);
else return Ack(m-1,Ack(m,n-1));
}

Here is some non-recursive python code that computes the same thing (note that it requires a stack-like data structure):
def ack(m,n):
if n < 0 or m < 0:
return 0
next_m = []
while m != 0 or (m==0 and next_m!=[]):
if (m==0 and next_m!=[]):
m = next_m.pop()
n = n+1
continue
if n==0:
m = m-1
n = 1
else:
n = n-1
next_m.append(m-1)
return n+1

Related

Count the number of ways a given sequence of digits can be split with each part at most K

Hi guys I'm practicing dynamic programming and came across the following problem:
Given a number K, 0 <= K <= 10^100, a sequence of digits N, what is the number of possible ways of dividing N so that each part is at most K?
Input:
K = 8
N = 123
Output: 1
Explanation:
123
1-23
12-3
1-2-3
Are all possibilities of spliting N and only the last one is valid...
What I have achieved so far:
Let Dp[i] = the number of valid ways of dividing N, using i first digits.
Given a state, i must use the previous answer to compute new answers, we have 2 possibilities:
Use dp[i-1] + number of valid ways that split the digit i
Use dp[i-1] + number of valid ways that not split the digit i
But I'm stuck there and I don't know what to do
Thanks
Using dynamic programming implies that you need to think about the problem in terms of subproblems.
Let's denote by N[i...] the suffix of N starting at index i (for instance, with N = 45678955, we have N[3...] = 78955)
Let's denote by dp[i] the number of possible ways of dividing N[i...] so that each part is at most K.
We will also use a small function, max_part_len(N, K, i) which will represent the maximum length of a 'part' starting at i. For instance, with N = 45678955, K = 37, i = 3, we have max_part_len(N, K, i) = 1 because 7 < 37 but 78 > 37.
Now we can write the recurrence (or induction) relation on dp[i].
dp[i] = sum_(j from 1 to max_part_len(N, K, i)) dp[i+j]
This relation means that the the number of possible ways of dividing N[i...] so that each part is at most K, is:
The sum of the the number of possible ways of dividing N[i+j...] so that each part is at most K, for each j such that N[i...j] <= k.
From there the algorithm is quite straight forward if you understood the basics of dynamic programming, I leave this part to you ;-)
I think we can also use divide and conquer. Let f(l, r) represent the number of ways to divide the range of digits indexed from l to r, so that each part is at most k. Then divide the string, 45678955 in two:
4567 8955
and the result would be
f(4567) * f(8955)
plus a division with a part that includes at least one from each side of the split, so each left extension paired with all right extensions. Say k was 1000. Then
f(456) * 1 * f(955) + // 78
f(456) * 1 * f(55) + // 789
f(45) * 1 * f(955) // 678
where each one of the calls to f performs a similar divide and conquer.
Here's JavaScript code comparing a recursive (top-down) implementation of m.raynal's algorithm with this divide and conquer:
function max_part_len(N, K, i){
let d = 0;
let a = 0;
while (a <= K && d <= N.length - i){
d = d + 1;
a = Number(N.substr(i, d));
}
return d - 1;
}
// m.raynal's algorithm
function f(N, K, i, memo={}){
let key = String([N, i])
if (memo.hasOwnProperty(key))
return memo[key];
if (i == N.length)
return 1
if (i == N.length - 1)
return (Number(N[i]) <= K) & 1
let s = 0;
for (let j=1; j<=max_part_len(N, K, i); j++)
s = s + f(N, K, i + j, memo);
return memo[key] = s;
}
// divide and conquer
function g(N, K, memo={}){
if (memo.hasOwnProperty(N))
return memo[N];
if (!N)
return memo[N] = 1;
if (N.length == 1)
return memo[N] = (Number(N) <= K) & 1;
let mid = Math.floor(N.length / 2);
let left = g(N.substr(0, mid), K);
let right = g(N.substr(mid), K);
let s = 0;
let i = mid - 1;
let j = mid;
let str = N.substring(i, j + 1);
while (i >= 0 && Number(str) <= K){
if (j == N.length){
if (i == 0){
break;
} else{
i = i - 1;
j = mid;
str = N.substring(i, j + 1);
continue
}
}
let l = g(N.substring(0, i), K, memo);
let r = g(N.substring(j + 1, N.length, memo), K);
s = s + l * r;
j = j + 1;
str = N.substring(i, j + 1);
if (Number(str) > K){
j = mid;
i = i - 1;
str = N.substring(i, j + 1);
}
}
return memo[N] = left * right + s;
}
let start = new Date;
for (let i=5; i<100000; i++){
let k = Math.ceil(Math.random() * i)
let ii = String(i);
let ff = f(ii, k, 0);
}
console.log(`Running f() 100,000 times took ${ (new Date - start)/1000 } sec`)
start = new Date;
for (let i=5; i<100000; i++){
let k = Math.ceil(Math.random() * i)
let ii = String(i);
let gg = g(ii, k);
}
console.log(`Running g() 100,000 times took ${ (new Date - start)/1000 } sec`)
start = new Date;
for (let i=5; i<100000; i++){
let k = Math.ceil(Math.random() * i)
let ii = String(i);
let ff = f(ii, k, 0);
let gg = g(ii, k);
if (ff != gg){
console.log("Mismatch found.", ii, k, ff, gg);
break;
}
}
console.log(`No discrepancies found between f() and g(). ${ (new Date - start)/1000 } sec`)

Finding sum of fibonacci numbers recursively

I'm a bit stuck here. I know a particular fibonacci number can be found recursively as so:
int fib (int n)
{
if (n <= 1)
return n;
else
return fib(n-1) + fib(n-2);
}
And I know iteratively I could call that function n times to find the sum of fibonacci numbers
int sum = 0;
for (int i = 0; i < n; i++)
{
sum += fib(i);
}
But I'm having a hard time coming up with a recursive function to find the sum. I don't think it would be much different than the original fibonacci function. (This is for an assignment aimed at improving my ability to write ocaml syntax, not writing recursive functions)
Since no one else is bothering to answer your question, here you go:
int fib_sum(int n)
{
if (n == 0)
return 0;
if (n == 1)
return 1;
return fib_sum(n-1) + fib_sum(n-2) + 1;
}
If you want a recursive solution involving only fib_sum(), here is one:
int fib_sum (int n)
{
if (n == 0)
return 1;
if (n == 1)
return 2;
return fib_sum(n-1) + fib_sum(n - 2) + 1;
}
Observing that fib_sum(n) == fib(n+2) - 1 you can use more or less the same function.
I guess this will work fine
int fib_sum (int n){
if(n<=1) {
return n;
}
else {
return fib_Sum(n-1) + fib_Sum(n-2) + 1;
}
}
Keep in mind that counting of elements starts from 0
so elements 0 1 1 2 3 5 8 13
then position 0 1 2 3 4 5 6 7
So if n = 5, the sum = (0+1+1+2+3+5)=12
recursive function will be:
int fib_sum (int n){ if(n<=1) { return n; } else { return fib_Sum(n-1) + fib_Sum(n-2) + 1; } }

Efficiently evaluating a recursive function?

I came across with an interesting puzzle on my previous interview.
You need to implement a function which would fit the following conditions:
m, n - positive integer numbers > 0
F(m, n) = F(m-1, n-1) + F(m, n-1)
F(1, n) = 1
F(m, 1) = 1
Obviously you can write the recursive implementation:
int F(int m, int n)
{
if(m == 1) return 1;
if(n == 1) return 1;
return F(m-1, n-1) + F(m, n-1);
}
But for input data equals one billion it will run very long time because it will get 2^1000000000 iterations :)
Does anybody have any ideas how to optimize this solution?
function F(m, n)
v = 1
s = 1
k = 1
while k < m do
v = v * (n-k) / k
s = s + v
k = k + 1
end
return s
end

Determine if a sorted array contains a contiguous sequence that sums up to N

I'm trying to write an algorithm that will return True/False whether a contiguous sequence in a sorted array that contains only positive integers, can sum up to N.
For example:
Array = { 1, 2, 3, 4 };
6 is good! 1 + 2 + 3 = 6
8 is not good! 1 + 3 + 4 = 8, but it's not contiguous, since we skipped the 2.
This is what I have tried to do:
int[] arr = ...;
int headIndex = 1, tailIndex = 0, sum = arr[0];
while (sum != n)
{
if (sum < n)
{
sum += arr[headIndex++];
}
if (sum > n)
{
sum -= arr[tailIndex++];
}
}
return sum == n;
Obviously the above does not work (In some cases it might get stuck in an infinite loop). Any suggestions?
One thing I haven't mentioned earlier, and is very important- the algorithm's complexity must be low as possible.
This is just a sketch:
Loop from left to right, find the largest k that n1 + ... + nk <= target, set sum = n1 + ... + nk. If the array sum is smaller than target, then return false.
If sum == target, we are done. If not, then any subarray S that sum to target will have S.length < k, and will begin from an element that is larger than the first one. So we kick out the first from the sum: sum -= n1, leftEnd++. Now we can go back to step 1, but no need to compute k from scratch.
Since the left end moves at most N times, and the right end moves at most N times, this algorithm has time complexity O(N), and constant space requirement.
var i = 0;
while(i != arr.Length)
{
var remembre = i;
var tmp = 0;
for(; tmp < N && i < arr.Length; ++i)
tmp += arr[i];
if(N == tmp)
return true;
i = remembre + 1;
}
return false;
I believe this should work.
Simply:
for i = 1 to n - 1:
j = 0
while (j < i):
sm = 0
for k = j to i:
sm = sm + array[k]
if sm == N:
return True
j = j + 1
return False
This works in O(n^3) time.
Here is a solution in code. It's been heavily influenced by #Ziyao Wei's sketch, which simplified my original approach (in particular, there is no need to backtrack and add the small numbers back on, only to take them off as I first thought).
public static bool HasConsecutiveSum(IList<int> list, int requiredSum)
{
int start = 0;
int sum = 0;
for (int end = 0; end < list.Count; end++)
{
sum += list[end];
while (sum > requiredSum)
{
sum -= list[start++];
if (start > end)
{
return false;
}
}
if (sum == requiredSum)
{
return true;
}
}
return false;
}
I think the most optimal algorithm works with a window that moves over the list. The value of the window (WV) is the sum of the elements that fall within the window. If WV is less then N, move the head and add the new value that fits within the window to WV, if the value is bigger then N, move the tail one up and subtract the value that falls of the window from WV. The algorithm stops when WV equals N, or the tail moves beyond the head, or the head is at the end of the list, and WV is still to low.
This would run in linear time: every element in the list is once added and once subtracted at most.
Written down in some code to illustrate the idea (python alike), but not tested
WV = list[0]
L = len(list)
tail = 0
head = 0
while WV != N
if WV < N
head += 1
if head < L
WV += list[head]
else
return false // beyond end of list
elif WV > N
if tail < head
WV -= list[tail]
tail += 1
else
return false // single element bigger then N, and list is sorted
return true

LCS ALGORITHM ( example )

There's a dynamic programming algorithm to find the Longest Common Subsequence of two sequences. How can I find the LCS algorithm of two sequences X and Y. (Test of correctness)
(a) X = ABEDFEESTYH Y=ABEDFEESTYHABCDF
(b) X = BFAAAABBBBBJPRSTY Y=ABCDEFGHIJKLMNOPRS
(c) X = ϕ (Empty Sequence), Y = BABADCAB
Here is an online calculator
http://igm.univ-mlv.fr/~lecroq/seqcomp/node4.html
Java
public class LCS {
public static void main(String[] args) {
String x = StdIn.readString();
String y = StdIn.readString();
int M = x.length();
int N = y.length();
// opt[i][j] = length of LCS of x[i..M] and y[j..N]
int[][] opt = new int[M+1][N+1];
// compute length of LCS and all subproblems via dynamic programming
for (int i = M-1; i >= 0; i--) {
for (int j = N-1; j >= 0; j--) {
if (x.charAt(i) == y.charAt(j))
opt[i][j] = opt[i+1][j+1] + 1;
else
opt[i][j] = Math.max(opt[i+1][j], opt[i][j+1]);
}
}
// recover LCS itself and print it to standard output
int i = 0, j = 0;
while(i < M && j < N) {
if (x.charAt(i) == y.charAt(j)) {
System.out.print(x.charAt(i));
i++;
j++;
}
else if (opt[i+1][j] >= opt[i][j+1]) i++;
else j++;
}
System.out.println();
}
}
EDIT: C++ implementation: http://comeoncodeon.wordpress.com/2009/08/07/longest-common-subsequence-lcs/
There's a dynamic programming algorithm to find the Longest Common Subsequence of two sequences (assuming that's what you meant by LCS): http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
Here's the recurrence (from Wikipedia):
and the pseudocode (also from Wikipedia):
function LCSLength(X[1..m], Y[1..n])
C = array(0..m, 0..n)
for i := 0..m
C[i,0] = 0
for j := 0..n
C[0,j] = 0
for i := 1..m
for j := 1..n
if X[i] = Y[j]
C[i,j] := C[i-1,j-1] + 1
else:
C[i,j] := max(C[i,j-1], C[i-1,j])
return C[m,n]
It's then possible to reconstruct what the longest subsequences are from the C array (see the Wikipedia article).
I have written a implementation in Ruby. It's a extension of String Class :
class String
def lcs_with(str)
unless str.is_a? String
raise ArgumentError,"Need a string"
end
n = self.length + 1
m = str.length + 1
matrix = Array.new(n, nil)
matrix.each_index do |i|
matrix[i] = Array.new(m, 0)
end
1.upto(n - 1) do |i|
1.upto(m - 1) do |j|
if self[i] == str[j]
matrix[i][j] = matrix[i - 1][j - 1] + 1
else
matrix[i][j] = [matrix[i][j - 1], matrix[i - 1][j]].max
end
end
end
matrix[self.length][str.length]
end
end
puts "ABEDFEESTYH".lcs_with "ABEDFEESTYHABCDF"

Resources