I have been asked to analyze the asymptotic time complexity of the following recursion function:
for-all k ≥ 1:
T(n) = n + T(n/2) + T(n/4) + T(n/8) + .... + T(n/2^k)
I was able to prove that:
T(n) = O(n⋅log n) and T(n) = Ω(n),
but I am looking for a tighter bound (Big Theta).
First of all:
I understand "for-all k >= 1" this way: for k = 1 to k = m where 2m-1 ≤ n ≤ 2m.
So basicly m = log₂(n) holds.
Have a look at my calculation:
T(n) = n + Σk=1,...,m T(n/2k)
= n + T(n/2) + Σk=2,...,m T(n/2k)
= n + n/2 + 2⋅Σk=2,...,m T(n/2k)
= ...
= n + Σk=1,...,m k⋅n/2k
= n + n⋅Σk=1,...,m k/2k
= n + n⋅(2 - 2-mm - 21-m)
≤ n + 2⋅n
= 3n
So T(n) is in Θ(n).
Notice:
You can also approximate Σk=1,...,m k/2k by the integral s(m) = ∫1m k/2k dk.
And here limm → ∞s(m) = 2 also holds.
Related
Recurrence relations can be directly derived from a recursive algorithm, but
they are in a form that does not allow us to quickly determine how efficient
the algorithm is.
Please how can I solve this
T(n) = 6T(n/6) + 2n + 3 for n a power of 6 T(1) = 1 solution ?
This recurrence could be solved with rsolve from SymPy, Python's symbolic math library.
from sympy import Function, rsolve
from sympy.abc import k, n
f = Function('f')
g = Function('g')
# T(n) = 6T(n/6) + 2n + 3 for n a power of 6 T(1) = 1
T = f(n) - 6*f(n/6) - 2*n - 3
Tk = T.subs({n: 6**k, f(n): g(k), f(n/6):g(k-1)})
s = rsolve(Tk, g(k), {g(0): 1})
print ("solution for k:", s.cancel())
for k in range(0,11):
print(f"k={k}, n={6**k}, T(n)={2*6**k*k + (8*6**k - 3)//5}")
This gives:
Tk(k) = 2*6**k*k + 8*6**k/5 - 3/5 or Tk(k) = ((10k+8)6k - 3)/5
T(n) = 2*n*log(n)/log(6) + 8*n/5 - 3/5 or T(n) = ((n(10log6(n)+8) - 3)/5
First 11 values:
k=0, n=1, T(n)=1
k=1, n=6, T(n)=21
k=2, n=36, T(n)=201
k=3, n=216, T(n)=1641
k=4, n=1296, T(n)=12441
k=5, n=7776, T(n)=90201
k=6, n=46656, T(n)=634521
k=7, n=279936, T(n)=4367001
k=8, n=1679616, T(n)=29561241
k=9, n=10077696, T(n)=197522841
k=10, n=60466176, T(n)=1306069401
We can check the formulas via the recursive formulation:
def recursive_t(n):
if n == 1:
res = 1
else:
t_ndiv6 = recursive_t(n//6)
res = 6 * t_ndiv6 + 2 * n + 3
print(f"T({n})={res}")
return res
recursive_t(6**10)
This prints out the same values for the same n.
I have to calculate the computational complexity and computational complexity class of T(n) = T(n-1) + n.
My problem is that I don't know any method to do so and the only one I'm familiar with is universal recursion which doesn't apply to this task.
T(0) = a
T(n) = T(n-1) + n
n T(n)
---------
0 a
1 T(1-1) + n = a + 1
2 T(2-1) + n = a + 1 + 2
3 T(3-1) + n = a + 1 + 2 + 3
...
k T(k-1) + n = a + 1 + 2 + ... + k
= a + k(k+1)/2
Guess T(n) = O(n^2) based on the above. We can prove it by induction.
Base case: T(1) = T(0) + 1 = a + 1 <= c*1^2 provided that c >= a + 1.
Induction hypothesis: assume T(n) <= c*n^2 for all n up to and including k.
Induction step: show that T(k+1) <= c*(k+1)^2. We have
T(k+1) = T(k) + k + 1 <= c*k^2 + k + 1
<= c*k^2 + 2k + 1 // provided k >= 0
<= c*(k^2 + 2k + 1) // provided c >= 1
= c*(k+1)^2
We know k >= 0 and we can choose c to be the greater of a+1 and 1, which must reasonably be a+1 since T(0) is nonnegative.
How is the following recurrence relation solved:
T(n) = 2T(n-2)+O(1)
What I have tried so far is:
O(1) is lower or equal than a constant c.
So
T(n) <= 2T(n-2) + c
T(n) <= 4T(n-4) + 2c
T(n) <= 8T(n-6) + 3c
.
.
.
So a pattern is emerging... the general term is:
T(n) <= 2^k*T(n-2k) + kc
But I dont know how to continue from there.Any advice is appreciated.
Assuming your generalization for k is true[1]
T(n) <= 2^k*T(n-2k) + kc
For k=n/2 you get:
T(n) <= 2^n/2 * T(0) + n/2 * c = 2^(n/2) + n/2*c
Which is in O(sqrt(2^n))
Formal proof can be done with induction, with the induction hypothesis of:
T(n) <= 2^(n/2) + c*n
And step of:
T(n) = 2T(n-2) + c = (induction hypothesis)
T(n) = 2* 2^((n-2)/2) + (n-2)*c + c
T(n) = 2^ (n/2 - 2/2 + 1) + (n-1)*c
And indeed:
T(n) = 2^(n/2) + (n-1)*c <= 2^(n/2) + c*n
(1) It is not, it ignores the fact that the constant is multiplied in the loop.
I am having trouble understanding the concept of recurrences. Given you have T(n) = 2T(n/2) +1 how do you calculate the complexity of this relationship? I know in mergesort, the relationship is T(n) = 2T(n/2) + cn and you can see that you have a tree with depth log2^n and cn work at each level. But I am unsure how to proceed given a generic function. Any tutorials available that can clearly explain this?
The solution to your recurrence is T(n) ∈ Θ(n).
Let's expand the formula:
T(n) = 2*T(n/2) + 1. (Given)
T(n/2) = 2*T(n/4) + 1. (Replace n with n/2)
T(n/4) = 2*T(n/8) + 1. (Replace n with n/4)
T(n) = 2*(2*T(n/4) + 1) + 1 = 4*T(n/4) + 2 + 1. (Substitute)
T(n) = 2*(2*(2*T(n/8) + 1) + 1) + 1 = 8*T(n/8) + 4 + 2 + 1. (Substitute)
And do some observations and analysis:
We can see a pattern emerge: T(n) = 2k * T(n/2k) + (2k − 1).
Now, let k = log2 n. Then n = 2k.
Substituting, we get: T(n) = n * T(n/n) + (n − 1) = n * T(1) + n − 1.
For at least one n, we need to give T(n) a concrete value. So we suppose T(1) = 1.
Therefore, T(n) = n * 1 + n − 1 = 2*n − 1, which is in Θ(n).
Resources:
https://www.cs.duke.edu/courses/spring05/cps100/notes/slides07-4up.pdf
http://www.cs.duke.edu/~ola/ap/recurrence.html
However, for routine work, the normal way to solve these recurrences is to use the Master theorem.
On my midterm I had the problem:
T(n) = 8T(n/2) + n^3
and I am supposed to find its big theta notation using either the masters or alternative method. So what I did was
a = 8, b = 2 k = 3
log28 = 3 = k
therefore, T(n) is big theta n3. I got 1/3 points so I must be wrong. What did I do wrong?
T(n) = aT(n/b) + f(n)
You applied the version when f(n) = O(n^(log_b(a) - e)) for some e > 0.
This is important, you need this to be true for some e > 0.
For f(n) = n^3, b = 2 and a = 8,
n^3 = O(n^(3-e)) is not true for any e > 0.
So your picked the wrong version of the Master theorem.
You need to apply a different version of Master theorem:
if f(n) = Theta ((log n)^k * n^log_b(a)) for some k >= 0,
then
T(n) = Theta((log n)^(k+1) * n^log_b(a))
In your problem, you can apply this case, and that gives T(n) = Theta(n^3 log n).
An alternative way to solve your problem would be:
T(n) = 8 T(n/2) + n^3.
Let g(n) = T(n)/n^3.
Then
n^3 *g(n) = 8 * (n/2)^3 * g(n/2)+ n^3
i.e g(n) = g(n/2) + 1.
This implies g(n) = Theta(logn) and so T(n) = Theta(n^3 logn).