I have an algorithm
R(N)
{
if(n<=2) return n;
else
sum=0;
for i=1 to n-2
sum+=(n-1)*R(i)
return sum;
}
I want to get the recurrence for number of multiplications operations performed by R(n).
if
T(n)=0 for n<=2
what is T(n) for n>2?
In addition, how can I show an exponential lower bound on complexity of M(n)?
1) For n > 2:
T(n) = sum(f(i) + 1 for i from 1 to n - 2) =
n - 2 + sum(f(i) for i from 1 to n - 2)
The first equation is correct because R(1), R(2), ..., R(n - 2)
are called recursively and than one more multiplication is performed
after each call.
2)The proof for exponential lower bound:
a) Let's assume that g(i) is such a sequence that:
g(0) = 0
g(1) = 1
g(2) = 1
g(3) = 1
g(i) = g(i - 2) + g(i - 3) for i >= 4
Then g(i) <= R(i + 3) for any valid i, because
a formula for g(i) is obtained by removing n - 2 and g(1), g(2),...,g(i - 4) from
the right side of the recursive formula for R(and all terms are non-negative).
b) On the other hand, g(i) >= f(i / 2), where f(i) is a Fibonacci sequence
(here I assume that f(0) = 0, f(1) = 1, f(2) = 1 and so on).
Proof:
1) Base case: for i <= 4 this inequality holds true(one can simply check it).
2) Induction:
g(i) = g(i - 2) + g(i - 3) >= f((i - 2) / 2) + f((i - 3) / 2) >= f(i / 2 - 1) + f(i / 2 - 2) = f(i / 2).
c) Thus, f(i) <= g(i) <= R(i + 3) so R is lower bounded by Fibonacci sequence. And Fibonacci sequence grows exponentially!
Related
Question:
In less O(n) find a number K in sequence 1,2,3...N such that sum of 1,2,3...K is exactly half of sum of 1,2,3..N
Maths:
I know that the sum of the sequence 1,2,3....N is N(N+1)/2.
Therefore our task is to find K such that:
K(K+1) = 1/2 * (N)(N+1)/2 if such a K exists.
Pseudo-Code:
sum1 = n(n+1)/2
sum2 = 0
for(i=1;i<n;i++)
{
sum2 += i;
if(sum2 == sum1)
{
index = i
break;
}
}
Problem: The solution is O(n) but I need better such as O(n), O(log(n))...
You're close with your equation, but you dropped the divide by 2 from the K side. You actually want
K * (K + 1) / 2 = N * (N + 1) / (2 * 2)
Or
2 * K * (K + 1) = N * (N + 1)
Plugging that into wolfram alpha gives the real solutions:
K = 1/2 * (-sqrt(2N^2 + 2N + 1) - 1)
K = 1/2 * (sqrt(2N^2 + 2N + 1) - 1)
Since you probably don't want the negative value, the second equation is what you're looking for. That should be an O(1) solution.
The other answers show the analytical solutions of the equation
k * (k + 1) = n * (n + 1) / 2 Where n is given
The OP needs k to be a whole number, though, and such value may not exist for every chosen n.
We can adapt the Newton's method to solve this equation using only integer arithmetics.
sum_n = n * (n + 1) / 2
k = n
repeat indefinitely // It usually needs only a few iterations, it's O(log(n))
f_k = k * (k + 1)
if f_k == sum_n
k is the solution, exit
if f_k < sum_n
there's no k, exit
k_n = (f_k - sum_n) / (2 * k + 1) // Newton step: f(k)/f'(k)
if k_n == 0
k_n = 1 // Avoid inifinite loop
k = k - k_n;
Here there is a C++ implementation.
We can find all the pairs (n, k) that satisfy the equation for 0 < k < n ≤ N adapting the algorithm posted in the question.
n = 1 // This algorithm compares 2 * k * (k + 1) and n * (n + 1)
sum_n = 1 // It finds all the pairs (n, k) where 0 < n ≤ N in O(N)
sum_2k = 1
for every n <= N // Note that n / k → sqrt(2) when n → ∞
while sum_n < sum_2k
n = n + 1 // This inner loop requires a couple of iterations,
sum_n = sum_n + n // at most.
if ( sum_n == sum_2k )
print n and k
k = k + 1
sum_2k = sum_2k + 2 * k
Here there is an implementation in C++ that can find the first pairs where N < 200,000,000:
N K K * (K + 1)
----------------------------------------------
3 2 6
20 14 210
119 84 7140
696 492 242556
4059 2870 8239770
23660 16730 279909630
137903 97512 9508687656
803760 568344 323015470680
4684659 3312554 10973017315470
27304196 19306982 372759573255306
159140519 112529340 12662852473364940
Of course it becomes impractical for too large values and eventually overflows.
Besides, there's a far better way to find all those pairs (have you noticed the patterns in the sequences of the last digits?).
We can start by manipulating this Diophantine equation:
2k(k + 1) = n(n + 1)
introducing u = n + 1 → n = u - 1
v = k + 1 k = v - 1
2(v - 1)v = (u - 1)u
2(v2 - v) = u2 + u
2(4v2 - 4v) = 4u2 + 4u
2(4v2 - 4v) + 2 = 4u2 - 4u + 2
2(4v2 - 4v + 1) = (4u2 - 4u + 1) + 1
2(2v - 1)2 = (2u - 1)2 + 1
substituting x = 2u - 1 → u = (x + 1)/2
y = 2v - 1 v = (y + 1)/2
2y2 = x2 + 1
x2 - 2y2 = -1
Which is the negative Pell's equation for 2.
It's easy to find its fundamental solutions by inspection, x1 = 1 and y1 = 1. Those would correspond to n = k = 0, a solution of the original Diophantine equation, but not of the original problem (I'm ignoring the sums of 0 terms).
Once those are known, we can calculate all the other ones with two simple recurrence relations
xi+1 = xi + 2yi
yi+1 = yi + xi
Note that we need to "skip" the even ys as they would lead to non integer solutions. So we can directly use theese
xi+2 = 3xi + 4yi → ui+1 = 3ui + 4vi - 3 → ni+1 = 3ni + 4ki + 3
yi+2 = 2xi + 3yi vi+1 = 2ui + 3vi - 2 ki+1 = 2ni + 3ki + 2
Summing up:
n k
-----------------------------------------------
3* 0 + 4* 0 + 3 = 3 2* 0 + 3* 0 + 2 = 2
3* 3 + 4* 2 + 3 = 20 2* 3 + 3* 2 + 2 = 14
3*20 + 4*14 + 3 = 119 2*20 + 3*14 + 2 = 84
...
It seems that the problem is asking to solve the diophantine equation
2K(K+1) = N(N+1).
By inspection, K=2, N=3 is a solution !
Note that technically this is an O(1) problem, because N has a finite value and does not vary (and if no solution exists, the dependency on N is even meanignless).
The condition you have is that the sum of 1..N is twice the sum of 1..K
So you have N(N+1) = 2K(K+1) or K^2 + K - (N^2 + N) / 2 = 0
Which means K = (-1 +/- sqrt(1 + 2(N^2 + N)))/2
Which is O(1)
Please can anyone help me with this:
Solve using iteration Method T (n) = T (n - 1) + (n - 1)
And prove that T (n) ∈Θ (n²)
Please, if you can explain step by step I would be grateful.
I solved an easy way :
T (n) = T (n - 1) + (n - 1)-----------(1)
//now submit T(n-1)=t(n)
T(n-1)=T((n-1)-1)+((n-1)-1)
T(n-1)=T(n-2)+n-2---------------(2)
now submit (2) in (1) you will get
i.e T(n)=[T(n-2)+n-2]+(n-1)
T(n)=T(n-2)+2n-3 //simplified--------------(3)
now, T(n-2)=t(n)
T(n-2)=T((n-2)-2)+[2(n-2)-3]
T(n-2)=T(n-4)+2n-7---------------(4)
now submit (4) in (2) you will get
i.e T(n)=[T(n-4)+2n-7]+(2n-3)
T(n)=T(n-4)+4n-10 //simplified
............
T(n)=T(n-k)+kn-10
now, assume k=n-1
T(n)=T(n-(n-1))+(n-1)n-10
T(n)=T(1)+n^2-n-10
According to the complexity 10 is constant
So , Finally O(n^2)
T(n) = T(n - 1) + (n - 1)
= (T(n - 2) + (n - 2)) + (n - 1)
= (T(n - 3) + (n - 3)) + (n - 2) + (n - 1)
= ...
= T(0) + 1 + 2 + ... + (n - 3) + (n - 2) + (n - 1)
= C + n * (n - 1) / 2
= O(n2)
Hence for sufficient large n, we have:
n * (n - 1) / 3 ≤ T(n) ≤ n2
Therefore we have T(n) = Ω(n²) and T(n) = O(n²), thus T(n) = Θ (n²).
T(n)-T(n-1) = n-1
T(n-1)-T(n-2) = n-2
By substraction
T(n)-2T(n-1)+T(n-2) = 1
T(n-1)-2T(n-2)+T(n-3) = 1
Again, by substitution
T(n)-3T(n-1)+3T(n-2)-T(n-3) = 0
Characteristic equation of the recursion is
x^3-3x^2+3x-1 = 0
or
(x-1)^3 = 0.
It has roots x_1,2,3 = 1,
so general solution of the recursion is
T(n) = C_1 1^n + C_2 n 1^n + C_3 n^2 1^n
or
T(n) = C_1 + C_2 n + C_3 n^2.
So,
T(n) = Θ(n^2).
Here's the pseudocode:
Baz(A) {
big = −∞
for i = 1 to length(A)
for j = 1 to length(A) - i + 1
sum = 0
for k = j to j + i - 1
sum = sum + A(k)
if sum > big
big = sum
return big
So line 3 will be O(n) (n being the length of the array, A)
I'm not sure what line 4 would be...I know it decreases by 1 each time it is run, because i will increase.
and I can't get line 6 without getting line 4...
All help is appreciated, thanks in advance.
Let us first understand how first two for loops work
for i = 1 to length(A)
for j = 1 to length(A) - i + 1
First for loop will run from 1 to n(length of Array A) and the second for loop will depend on value of i. SO when i = 1 second for loop will run for n times..When i increments to 2 your second for loop will run for (n-1) time ..so it will go on till 1.
So your second for loop will run as follows:
n + (n - 1) + (n - 2) + (n - 3) + .... + 1 times...
You can use following formula: sum(1 to n) = N * (N + 1) / 2 which gives (N^2 + N)/2 So we have Big oh for these two loops as
O(n^2) (Big Oh of n square )
Now let us consider third loop also...
Your third for loop looks like this
for k = j to j + i - 1
But this actually means,
for k = 0 to i - 1 (you are just shifting the range of values by adding/subtracting j but number of times the loop should run will not change, as difference remains same)
So your third loop will run from 0 to 1(value of i) for first n iterations of second loop then it will run from 0 to 2(value of i) for first (n - 1) iterations of second loop and so on..
So you get:
n + 2(n-1) + 3(n-2) + 4(n-3).....
= n + 2n - 2 + 3n - 6 + 4n - 12 + ....
= n(1 + 2 + 3 + 4....) - (addition of some numbers but this can not be greater than n^2)
= `N(N(N+1)/2)`
= O(N^3)
So your time complexity will be N^3 (Big Oh of n cube)
Hope this helps!
Methodically, you can follow the steps using Sigma Notation:
Baz(A):
big = −∞
for i = 1 to length(A)
for j = 1 to length(A) - i + 1
sum = 0
for k = j to j + i - 1
sum = sum + A(k)
if sum > big
big = sum
return big
For Big-O, you need to look for the worst scenario
Also the easiest way to find the Big-O is to look into most important parts of the algorithm, it can be loops or recursion
So we have this part of the algorithm consisting of loops
for i = 1 to length(A)
for j = 1 to length(A) - i + 1
for k = j to j + i - 1
sum = sum + A(k)
We have,
SUM { SUM { i } for j = 1 to n-i+1 } for i = 1 to n
= 1/6 n (n+1) (n+2)
= (1/6 n^2 + 1/6 n) (n + 2)
= 1/6 n^3 + 2/6 2 n^2 + 1/6 n^2 + 2/6 n
= 1/6 n^3 + 3/6 2 n^2 + 2/6 n
= 1/6 n^3 + 1/2 2 n^2 + 1/3 n
T(n) ~ O(n^3)
Given the following function:
Function f(n,m)
if n == 0 or m == 0: return 1
return f(n-1, m) + f(n, m-1)
What's the runtime compexity of f? I understand how to do it quick and dirty, but how to properly characterize it? Is it O(2^(m*n))?
This is an instance of Pascal's triangle: every element is the sum of the two elements just above it, the sides being all ones.
So f(n, m) = (n + m)! / (n! . m!).
Now to know the number of calls to f required to compute f(n, m), you can construct a modified Pascal's triangle: instead of the sum of the elements above, consider 1 + sum (the call itself plus the two recursive calls).
Draw the modified triangle and you will quickly convince yourself that this is exactly 2.f(n, m) - 1.
You can obtain the asymptotic behavior of the binomial coefficients from Stirling's approximation. http://en.wikipedia.org/wiki/Binomial_coefficient#Bounds_and_asymptotic_formulas
f(n, m) ~ (n + m)^(n + m) / (n^n . m^m)
The runtime of f(n, m) is in O(f(n, m)). This is easily verified by the following observation:
Function g(n, m):
if n=0 or m=0: return 1
return g(n-1, m) + g(n, m-1) + 1
The function f is called equally often as g. Furthermore, the function g is called exactly g(n, m) times to evaluate the result of g(n, m). Likewise, the function f is called exactly g(n, m) = 2*f(n, m)-1 times in order to evaluate the result of f(n, m).
As #Yves Daoust points out in his answer, f(n, m) = (n + m)!/(n!*m!), therefore you get a non-recursive runtime of O((n+m)!/(n!*m!)) for f.
Understanding the Recursive Function
f(n, 0) = 1
f(0, m) = 1
f(n, m) = f(n - 1, m) + f(n, m - 1)
The values look like a Pascal triangle to me:
n 0 1 2 3 4 ..
m
0 1 1 1 1 1 ..
1 1 2 3 4
2 1 3 6
3 1 4 .
4 1 .
. .
. .
Solving the Recursion Equation
The values of Pascal's triangle can be expressed as binomial coefficients. Translating the coordinates one gets the solution for f:
f(n, m) = (n + m)
( m )
= (n + m)! / (m! (n + m - m)!)
= (n + m)! / (n! m!)
which is a nice term symmetric in both arguments n and m. (Final term first given by #Yves Daoust in this discussion)
Pascal's Rule
The recursion equation of f can be derived by using the symmetry of the binomial coefficients and Pascal's Rule
f(n, m) = (n + m)
( n )
= (n + m)
( m )
= ((n + m) - 1) + ((n + m) - 1)
( m ) ( m - 1 )
= ((n - 1) + m) + (n + (m - 1))
( m ) ( m )
= f(n - 1, m) + f(n, m - 1)
Determing the Number of Calls
The "number of calls of f" calculation function F is similar to f, we just have to add the call to f itself and the two recursive calls:
F(0, m) = F(n, 0) = 1, otherwise
F(n, m) = 1 + F(n - 1, m) + F(n, m - 1)
(Given first by #blubb in this discussion).
Understanding the Number of Calls Function
If we write it down, we get another triangle scheme:
1 1 1 1 1 ..
1 3 5 7
1 5 11
1 7 .
1 .
.
.
Comparing the triangles value by value, one guesses
F(n, m) = 2 f(n, m) - 1 (*)
(Result first suggested by #blubb in this discussion)
Proof
We get
F(0, m) = 2 f(0, m) - 1 ; using (*)
= 1 ; yields boundary condition for F
F(n, 0) = 2 f(n, 0) - 1
= 1
as it should and examining the otherwise clause, we see that
F(n, m) = 2 f(n, m) - 1 ; assumption
= 2 ( f(n - 1, m) + f(n, m - 1) ) - 1 ; definition f
= 1 + (2 f(n - 1, m) - 1) + (2 f(n, m - 1) - 1) ; algebra
= 1 + F(n - 1, m) + F(n, m - 1) ; 2 * assumption
Thus if we use (*) and the otherwise clause for f, the otherwise clause for F results.
As the finite difference equation and the start condition for F hold, we know it is F (uniqueness of the solution).
Estimating the Asymptotic Behaviour of the Number of Calls
Now on calculating / estimating the values of F (i.e. the runtime of your algorithm).
As
F = 2 f - 1
we see that
O(F) = O(f).
So the runtime of this algorithm is
O( (n + m)! / (n! m!) )
(Result first given by #Yves Daoust in this discussion)
Approximating the Runtime
Using the Stirling approximation
n! ~= sqrt(2 pi n) (n / e)^n
one can get a form without hard to calculate factorials. One gets
f(n, m) ~= 1/(2 pi) sqrt((n+m) / (n m)) [(n + m)^(n + m)] / (n^n m^m)
thus arriving at
O( sqrt((n + m) / (n m)) [(n + m)^(n + m)] / (n^n m^m) )
(Use of Stirling's formula first suggested by #Yves Daoust in this discussion)
procedure matrixvector(n:integer);
var i,j:integer;
begin
for i<-1 to n do begin
B[i] = 0;
C[i] = 0;
for j<-1 to i do
B[i]<- B[i]+ A[i,j];
for j<-n down to i+1 do
C[i]<-C[i] + A[i,j]
end
end;
O(n^2), if I read it right.
Why you need two inner loops is beyond me. Why not sum B and C in the same loop?
Let us trace the number of times each loop executes in each iteration.
procedure matrixvector(n : integer);
var i, j : integer;
begin
for i<-1 to n do begin // OuterLoop
B[i] = 0;
C[i] = 0;
for j <- 1 to i do // InnerLoop_1
B[i] <- B[i] + A[i, j];
for j <- n down to (i + 1) do // InnerLoop_2
C[i] <- C[i] + A[i, j]
end
end;
InnerLoop_1
In the first iteration of OuterLoop (i = 1), InnerLoop_1 executes once.
In the second iteration of OuterLoop (i = 2), InnerLoop_1 executes twice.
In the third iteration of OuterLoop (i = 3), InnerLoop_1 executes thrice.
.
.
.
In the last iteration of OuterLoop (i = n), InnerLoop_1 executes n times.
Therefore, the total number of times this code executes is
1 + 2 + 3 + … + n
= (n(n + 1) / 2) (Sum of Natural Numbers Formula)
= (((n^2) + n) / 2)
= O(n^2)
InnerLoop_2
In the first iteration of OuterLoop (i = 1), InnerLoop_2 executes n - 1 times.
In the second iteration of OuterLoop (i = 2), InnerLoop_2 executes n - 2 times.
In the third iteration of OuterLoop (i = 3), InnerLoop_2 executes n - 3 times.
.
.
.
In the n - 2th iteration of OuterLoop (i = n - 2), InnerLoop_2 executes 2 times.
In the n - 1th iteration of OuterLoop (i = n - 1), InnerLoop_2 executes 1 time.
In the last (nth) iteration of OuterLoop (i = n), InnerLoop_2 executes 0 times.
Therefore, the total number of times this code executes is
n - 1 + n - 2 + n - 3 + … + 2 + 1 + 0
= 0 + 1 + 2 + … + n - 3 + n - 2 + n - 1
= (n - 1)((n - 1) + 1) / 2 (Sum of Natural Numbers Formula)
= (n - 1)(n) / 2
= (((n^2) - n) / 2)
= O(n^2)
Time Complexity
Number of times InnerLoop_1 executes : (((n^2) + n) / 2)
Number of times InnerLoop_2 executes : (((n^2) - n) / 2)
Adding, we get
(((n^2) + n) / 2) + (((n^2) - n) / 2)
= ((((n^2) + n) + ((n^2) - n)) / 2)
= (((n^2) + n + (n^2) - n) / 2)
= (((n^2) + (n^2)) / 2)
= ((2(n^2)) / 2)
= (n^2)
= O(n^2)
——————
Also, do take a look at these
https://stackoverflow.com/a/71537431/17112163
https://stackoverflow.com/a/71146522/17112163
https://stackoverflow.com/a/69821878/17112163
https://stackoverflow.com/a/72046825/17112163
https://stackoverflow.com/a/72046933/17112163
Just explaining in detail for beginners:
Outermost for loop will run n times (0 to n)
Then there are two for loops within the out ermost for loop.
First for loop will go from 1 to n (1+2+3+4+.....+n)
And the second for loop will go from n to 1 (n+n-1+n-2+....+1)
The summation formula for (1+2+3+4+5+....+n ) is n(n+1)/2
so the total running time can be computed as n + n(n+1)/2 + n(n+1)/2
Observe the highest polynomial in this equation, it is n^2.
We can further simplify this equation and drop the constants and ignore the linear part, which will give us a run time of n^2.
worst case is O(n²).
there are indeed three loops, but not all inside each other, thus giving O(n²).
also, you can clearly see that the inner loops won't go from 1 to n (like the outer loop does). But because this would only change the time complexity by some constant, we can ignore this and say that it is just O(n^2).
This shows that time complexity is a measure saying: your algorithm will scale with this order, and it won't ever take any longer. (faster is however always possible)
for more information about "calculating" the worst case complexity of any algorithm, I can point you to a related question I asked earlier