Rewrite Resurrence Function to the Idea of Dynamic Programming - time-complexity

Can someone help me?
Rewrite the pseudo-code of Count(n) using the idea of Dynamic Programming. And determine the Time Complexity.
Test(n)
If n=1 return 1
Tn=0
For k=1 to n-1
Tn = Tn + Test(k) * Test(n-k)
Return Tn

Add Memoization to get a DP solution from a recursion one:
Python Code:
d = {}
def test(n):
if n == 1:
return 1
if d.get(n) is not None:
return d[n]
ans = 0
for k in range(1, n):
ans += test(k) * test(n - k)
d[n] = ans
return ans
You can check(It's Catalan numbers indeed, learn more about it in OEIS):
for i in range(1, 10):
print str(i) + ' ' + str(test(i))
Output:
1 1
2 1
3 2
4 5
5 14
6 42
7 132
8 429
9 1430
Time Complexity is O(n^2). Because calculate a state is O(n)(for k from 1 to n - 1), and we need calculate n state in total to get test(n).
In fact, we can achieve a O(n) solution since it's Catalan numbers...

Related

What will be the time complexity of for(int i=n;i>n/2;i=i/2) and For for(int i=n;i>0;i=i/2) ? with mathematical solution

While finding time complexities I can find the time complexity of any loop but not able to proof or understand it mathematically for eg : for(i = 0 ; i > n ; i /= 2) have O(log n) but how can i find and proof it mathematically, Please help me to understand this.
Correciting the loop for(i = n ; i > 0 ; i /= 2)
First of all, I think the loop you want to ask about is this:
for (i = n; i > 0; i /= 2)
A simple empirical way to figure out the complexity is to simply relate the bound of the loop n to the number of times the loop executes. For example, if n = 16, then i would take the following values:
i | loop iteration
16 | 1
8 | 2
4 | 3
2 | 4
1 | 5
So for an input of n = 16, there are roughly 4 steps:
2^4 = n
log_2(n) = 4
=> number of iterations is log_2(n)

What is the complexity of this function in terms of n?

f(n):
s = 1
m = n
while m >= 1:
for j in 1,2,3, .., m:
s = s + 1
m = m / 2
My attempt
How many times does the statement s = s + 1 run? Well, let's try a number or two for n and see what we get.
n = 32
m = n = 32
m = 32 => inner for loop, loops 32 times
m = 16 => -.- 16 times
m = 8 => -.- 8 times
m = 4 => -.- 4 times
m = 2 => -.- 2 times
m = 1 => -.- 1 time
In total 16+8+4+2+1 = 31 times for n = 32
Doing the same for n = 8 gives 15 times
Doing the same for n = 4 gives 7 times
Doing the same for n = 64 gives 127 times
Notice how it always seemingly is 2 * n - 1, I believe this to be no coincidence because what we're really observing is that the total amount of times the statement gets executed is equal to the geometric sum sum of 2^k from k=0 to k=log(n) which has a closed form solution 2n + 1 given that we're using base 2 logarithm.
As such, my guess is that the complexity is O(n).
Is this correct?
Well what you just observed is true indeed. We can prove it mathematically as well.
Inner loop execution for first iteration -> n
Inner loop execution for second iteration -> n/2
Inner loop execution for third iteration -> n/(2^2)
and so on....
Therfore total time is (n + (n/2) + (n/(2^2)) + ... + (n/(2^k))) where n/(2^k) should be equal to 1 which implies k = log(n). Taking n common from all terms will give us a GP And now using GP formulae in above series , total time will come out to be 1(1 - ((1/2)^k)) / (1 - 1/2). putting value of k = log(n), we will get total time as 2*(n-1).
Note -:
This gives us time complexity of O(n).
log is of base 2.

McDonald's sells Chicken McNuggets only in packages of 6, 9 or 20. What is the largest number of McNuggets that cannot be bought exactly?

Question is from MIT OCW Course Number 6.00, As Taught in Fall 2008:
Here is a theorem below:
If it is possible to buy x, x+1,…, x+5 sets of McNuggets, for some x, then it is possible to buy any number of McNuggets >= x, given that McNuggets come in 6, 9 and 20 packs.
Using the theorem above, write an exhaustive search to find the largest number of McNuggets that cannot be bought in exact quantity, i.e. write an iterative program that finds the largest number of McNuggets that cannot be bought in exact quantity. Format of search should follow the outline below:
Hypothesise possible instances of numbers of McNuggets that cannot be purchased exactly, starting with 1.
For each possible instance, called n, test if there exists non-negative integers a, b, and c, such that 6a+9b+20c = n.
If n McNuggets cannot be bought in exact quantity, save n.
When have found 6 consecutive values of n where 6a+9b+20c = n, the last answer that was saved (not the last value of n that had a solution) is the correct answer, since from the theorem, any amount larger than this saved value of n can also be bought in exact quantity
The error is in line 14 of the code below and this is the error:
elif(6*a + 9*b + 20*c < n_saved or 6*a + 9*b + 20*c > n_saved):
^
SyntaxError: invalid syntax
Here is the code:
def largest_not(a, b, c, n, n_saved):
a = 0
b = 0
c = 0
n = 0
n_saved = 0
for a in range (10):
for b in range (10):
for c in range (10):
for n in range (10):
for n_saved in range (10):
if (6*a + 9*b + 20*c == n):
print (n)
elif(6*a + 9*b + 20*c < n_saved or 6*a + 9*b + 20*c > n_saved):
print (n_saved)
if (n - n_saved > 5):
print "Largest number of McNuggets that cannot be bought in exact quantity: " + "<" + n_saved + ">"
else :
print "Have not found the largest number of McNuggets that cannot be bought in exact quantity."
a=6
b=9
c=20
largest_not(a, b, c, n, n_saved)
Here is a way to solve this:
def check(n):
"""check if n nuggets can be bought exactly with packs of 6, 9 and 20"""
for a in range(20):
for b in range(20):
for c in range(20):
if (6*a+9*b+20*c==n):
return True
return False
### look for a serie of 6 successives n
### to apply the theorem
nb_i = 0 ## number of successive good n found
sv_i = 0 ## last good n found
bad_i = 0 ## last bad n found
for i in range(1, 100):
if (check(i)):
nb_i+=1
sv_i=i
else:
bad_i=i
nb_i=0
sv_i=0
if nb_i==6:
print "Solved: the biggest number of nuggets you cannot buy exactly is: " + bad_i
break
result is:
Solved: the biggest number of nuggets you cannot buy exactly is: 43
Your elif needs to be inline with your if. However, your algorithm will also not work.
I got 43 as the largest number not possible: I'm sure this solution could be optimised.
def check(n):
# a in [0..max times 6 goes into n]
for a in range(0, n // 6 + 1):
# b in [0..max times 9 goes into remainder]
for b in range((n - 6*a) // 9 + 1):
# c in [0..max times 20 goes into remainder]
for c in range(0, (n - 6*a - 9*b) // 20 + 1):
if 6*a + 9*b + 20*c == n:
return (a, b, c)
return None
def largest_not():
n = 1
last_n_not_possible = 1
while (n - last_n_not_possible <= 6):
can_purchase = check(n)
if can_purchase is not None:
print("Can purchase ", n, ' = ', can_purchase[0],'*6 + ', can_purchase[1],'*9 + ', can_purchase[2], '*20', sep='')
else:
print("Can't purchase", n)
last_n_not_possible = n
n = n + 1
return last_n_not_possible
print("Answer: ", largest_not())

Why is the second line executed n (n + 1 / 2)

1. for i = 1 to n
2. for j = i + 1 to n
[...]
Why does my textbook say that the second line is executed n (n + 1 / 2) + 1 times?
I know that the first line will be executed n + 1 times because the + 1 will break the loop
The nested loop iteration count will be reduced by one each time ( see the picture below). Nevertheless , the whole code is in O(n^2). O(n*( (n+1)/2) = O( n*n/2+n/2) =O(n^2)
n=5
*****
****
***
**
*
The outer loop will result in n iterations of the inner loop. Each of these iterations will result in n-i loops. Since i ranges from i to n this thus results in a sum that looks like:
n + n-1 + n-2 + ... 1
This is a known sum. The sum of i with i from 1 to n is the same as:
n
---
\ n * (n + 1)
/ i = -----------
--- 2
i=1

Calculating the time complexity

Can somebody help with the time complexity of the following code:
for(i = 0; i <= n; i++)
{
for(j = 0; j <= i; j++)
{
for(k = 2; k <= n; k = k^2)
print("")
}
a/c to me the first loop will run n times,2nd will run for(1+2+3...n) times and third for loglogn times..
but i m not sure about the answer.
We start from the inside and work out. Consider the innermost loop:
for(k = 2; k <= n; k = k^2)
print("")
How many iterations of print("") are executed? First note that n is constant. What sequence of values does k assume?
iter | k
--------
1 | 2
2 | 4
3 | 16
4 | 256
We might find a formula for this in several ways. I used guess and prove to get iter = log(log(k)) + 1. Since the loop won't execute the next iteration if the value is already bigger than n, the total number of iterations executed for n is floor(log(log(n)) + 1). We can check this with a couple of values to make sure we got this right. For n = 2, we get one iteration which is correct. For n = 5, we get two. And so on.
The next level does i + 1 iterations, where i varies from 0 to n. We must therefore compute the sum 1, 2, ..., n + 1 and that will give us the total number of iterations of the outermost and middle loop: this sum is (n + 1)(n + 2) / 2 We must multiply this by the cost of the inner loop to get the answer, (n + 1)(n + 2)(log(log(n)) + 1) / 2 to get the total cost of the snippet. The fastest-growing term in the expansion is n^2 log(log(n)) and so that is what would typically be given as asymptotic complexity.