how to solve recursion of given algorithm? - algorithm

int gcd(n,m)
{
if (n%m ==0) return m;
n = n%m;
return gcd(m,n);
}
I solved this and i got
T(n, m) = 1 + T(m, n%m) if n > m
= 1 + T(m, n) if n < m
= m if n%m == 0
I am confused how to proceed further to get the final result. Please help me to solve this.

The problem here is that the size of the next values of m and n depend on exactly what the previous values were, not just their size. Knuth goes into this in detail in "The Art of Computer Programming" Vol 2: Seminumerical algorithms, section 4.5.3. After about five pages he proves what you might have guessed, which is that the worst case is when m and n are consecutive fibonacci numbers. From this (or otherwise!) it turns out that in the worst case the number of divisions required is linear in the logarithm of the larger of the two arguments.
After a great deal more heavy-duty math, Knuth proves that the average case is also linear in the logarithm of the arguments.

mcdowella has given a perfect answer to this.
For an intuitive explaination you can think of it this way,
if n >= m, n mod m < n/2;
This can be shown as,
if m < n/2, then:
n mod m < m < n/2
if m > n/2, then: n mod m = n-m < n/2
So effectively you are halving the larger input, and in two calls both the arguments will be halved.

Related

Algorithm Analysis: Big-O explanation

I'm currently taking a class in algorithms. The following is a question I got wrong from a quiz: Basically, we have to indicate the worst case running time in Big O notation:
int foo(int n)
{
m = 0;
while (n >=2)
{
n = n/4;
m = m + 1;
}
return m;
}
I don't understand how the worst case time for this just isn't O(n). Would appreciate an explanation. Thanks.
foo calculates log4(n) by dividing n by 4 and counting number of 4's in n using m as a counter. At the end, m is going to be the number of 4's in n. So it is linear in the final value of m, which is equal to log base 4 of n. The algorithm is then O(logn), which is also O(n).
Let's suppose that the worst case is O(n). That implies that the function takes at least n steps.
Now let's see the loop, n is being divided by 4 (or 2²) at each step. So, in the first iteration n is reduced to n/4, in the second, to n/8. It isn't being reduced linearly. It's being reduced by a power of two so, in the worst case, it's running time is O(log n).
The computation can be expressed as a recurrence formula:
f(r) = 4*f(r+1)
The solution is
f(r) = k * 4 ^(1-r)
Where ^ means exponent. In our case we can say f(0) = n
So f(r) = n * 4^(-r)
Solving for r on the end condition we have: 2 = n * 4^(-r)
Using log in both sides, log(2) = log(n) - r* log(4) we can see
r = P * log(n);
Not having more branches or inner loops, and assuming division and addition are O(1) we can confidently say the algorithm, runs P * log(n) steps therefore is a O((log(n)).
http://www.wolframalpha.com/input/?i=f%28r%2B1%29+%3D+f%28r%29%2F4%2C+f%280%29+%3D+n
Nitpickers corner: A C int usually means the largest value is 2^32 - 1 so in practice it means only max 15 iterations, which is of course O(1). But I think your teacher really means O(log(n)).

How to perform the big O analysis

Below is my code.
How can you perform the big O analysis for intDiv(m-n, n), where m & n are two random inputs?
intDiv(int m, int n) {
if(n>m)
return 0;
else
return 1 + intDiv(m-n, n);
} //this code finds the number of times n goes into m
It depends on the values of the m and n. In general, The number of steps involved for any pair of (m,n), such that n, m >=0 are integer_ceil(m/n).
Therefore, the time complexity of the above algorithm : O([m/n]), where, [] represents the ceil of the number.
I think it totally depends on n and m. For example if n=1 then it it is O(m). And when n=m/2 then it is O(log(m)).

Time complexity of gcd algorithm in terms of big theta notation.

Here n>m.
I have analyzed the worst case when n = fibonacci Nth term and m = fiboncci (N-1)th term.In this case total work will be proportinal to N or time complexity will be O(N).But I am interested in finding time complexity(theta notation) in terms of n.But I am not getting how to find relation between n and N or the upper and lower bound in terms of n.
int gcd(int n, int m) {
if (n%m ==0) return m;
if (n < m) swap(n, m);
while (m > 0) {
n = n%m;
swap(n, m);
}
return n;
}
Please help.
I would try to analyse how m changes after two iterations of the loop. One iteration might change n very little, for example (1001, 1000) -> (1000, 1). m might also change very little, for example (1999, 1000) -> (1000, 999). So analysing how either changes in a single iteration gives you very little. However, if you have two iterations then you will always have a big change.
So analyse this: If r = n/m, how does m change after two iterations of the algorithm, depending on r? By which factor does it decrease at least? (By the way, what is r for Fibonacci numbers? Does that explain the worst case? )
You might find this interesting.
It tries to explain Lamé's theorem for the number of steps of the GCD algorithm. The worst case is when the 2 numbers are consecutive Fibonacci numbers.

What is the exact complexity of this program?

Someone give me this piece of code and I am suppose to find the exact complexity, or in other words to find a formula that for a specific n to know how to calculate L.
L = 0;
for (i = 1; i<n; i++)
for (j = 1; j<i; j++)
for (k = j; k<n; k++)
L++;
My first thoughts were (n^3 + n^2)/2, but are wrong.
For example n=5 L=20 ;
n=10 L=240
Thanks :D
Edit:
This problem is from Fundamentals of Algorithms, page 140 or slide 161 in pdf (this is a free book version)
http://www.freebookspot.es/Comments.aspx?Element_ID=76025
Firstly: complexity is not about concrete numbers of n. It is about asymptotic behaviour. When one says that complexity of algorithm is O(f(n)), it doesn't mean that algorithm do strictly f(n) operations. In fact, it could do 2*f(n) or 1/2 * f(n) or f(n) + sqrt(f(n)). When talking about complexity one usually is interested in how fast number of operations grow with growth of input.
In your case you have to write 3 nested sums (one for each loop) and sum cost of inner operation (assume it's 1):
And this is exact formula (don't believe me — check using wolfram|alpha), but in complexity language it would be just O(n^3)
UPD: notice that this formula corresponds to the loops with condition of type less-or-equal rather than just less-than.
This is mathematics, not programming.
L is equal to (S is big-sigma, the sum):
n-1 i-1 n-1
S S S 1
i=1 j=1 k=j
n-1 i-1
= S S (n - j)
i=1 j=1
n-1 i-1 n-1 i-1
= S S n - S S j
i=1 j=1 i=1 j=1
n-1 n-1
= n * S (i-1) - S (i-1)i/2
i=1 i=1
And so on. You need to know that the sum of the first n integers is n(n+1)/2 and that the sum of the first n squares is n(n+1)(2n+1)/6. You'll end up with a cubic equation in n.
Thanks to Barmaley's answer for pointing out that I'm not an undergraduate any more, I don't have to manipulate formulae to simplify them down. Wolfram Alpha will do it for me ;-)
The answer is n(n-1)(n-2)/3. Usually when these things factorize nicely, it turns out that there's a key insight (perhaps a geometrical one) that I could have made early on, to get the answer out without writing too many long expressions. This result looks suspiciously like the volume of a pyramid inscribed in a cuboid with sides n, n-1, n-2.

How to prove logarithmic complexity

for (int i = 1; i < N; i *= 2) { ... }
Things like that are the signatures of logarithmic complexity.
But how get log(N)?
Could you give mathematical evidence?
Useful reference on algorithmic complexity: http://en.wikipedia.org/wiki/Big_O_notation
On the nth iteration,
i = 2^n
We know that it iterates until i >= N
Therefore,
i < N
Now,
2^n = i < N
N > 2^n
log2 N > log2 (2^n)
log2 N > n
We know it iterates n times, being less than log2 N.
Thus # iterations < log2 N, or # iterations is O(log N)
QED. Logarithmic complexity.
Multiplying N by 2 adds one more iteration, regardless of the size of N. That's pretty much the definition of the log function -- it goes up by a constant amount every time you multiply N by a constant.
Your code will work untill i < N, and each step i *= 2. We say your loop has logarithmic complexity if it runs log(N) + const times. 2 ^ log(N) = N, so after [log(N)] + 1 times i > N.

Resources