Reputation: 71
Can you please help me with calculating the running time of this function?
My guess would be O(n log n) n for the for-loop, and log n for the while loop.
But what makes me unsure is the j = j*3. if it would have been j = j/2, then I would have been sure of my answer.
Is it log n even though it is j = j*3 or j = j/3?
Upvotes: 2
Views: 110
Reputation: 2855
If it's j = j*3
, then the complexity will just be O(n*log_3(n))
instead of O(n*log_2(n))
for j = j*2
because they only differ by a constant factor which will be absorbed under Big-O
notation.
Coming to your function, the outer loop is surely O(n)
but the inner loop is not completely log_3(n)
every time. It's actually decreasing with every iteration. The expansion will be:
log_3(n) + log_3(n-1) + log_3(n-2) + ... + log_3(1)
Ignoring bases because of the reason explained above, we can write:
log(n) + log(n-1) + log(n-2) + ... + log(1)
One method to evaluate this is to upper bound each of the above terms by log(n)
, i.e.,
log(n) + log(n-1) + log(n-2) + ... + log(1) <= log(n) + log(n) + log(n) + ... + log(n)
<= n*log(n)
Thus, the complexity can be written as O(n*log(n))
.
Second method is as follows. Rewriting the above equation, we have:
log(n) + log(n-1) + log(n-2) + ... + log(1)
= log(n*(n-1)*(n-2)...1)
= log(n!)
Thus, for sure, the complexity can be written as O(log(n!))
. But what about log(n!)
? According to Stirling's approximation,
log(n!) ~ n*log(n) - n + O(log(n))
Note that, according to Wikipedia:
It is a very powerful approximation, leading to accurate results even for small values of n.
Thus, I can assume that this will be very much accurate for large values of n
(the case that we actually care about). Clearly, in the above approximation, the value of n*log(n)
dominates the other terms, thus, in Big-O
notation, I can write:
O(log(n!)) = O(n*log(n))
Upvotes: 1
Reputation: 195
A tighter upper-bound would be O(n). Because the total time is ( Sum(i=1 to n) of (log(n/i)) ) = log(n^n/n!) = O(n) The running time is actually Θ(n) if that matters.
Upvotes: 1
Reputation: 520
Time complexity of nested loops is equal to the number of times the innermost statement is executed. For example :
for ( int i = 1; i <= n; i ++ ) {
for ( int j = 1; j <= n; j ++ ) {
// O(1) expressions
}
}
In this situation (log_3(n)) you can test it with a small c++ code like this:
int main()
{
const int N = 10;
int j;
int count = 0;
int totalCount = 0;
for ( int i = 1; i <= N; i++ ) {
j = i;
while ( j <= N ) {
j = j * 3;
count++;
}
std::cout << " " << i <<"th iteration of outer loop : inner loop will iterate " << count << " times" << std::endl;
totalCount += count;
count = 0;
}
std::cout << "TOTAL COUNT is : " << totalCount << std::endl;
return 0;
}
Where you get results like this:
1th iteration of outer loop : inner loop will iterate 3 times
2th iteration of outer loop : inner loop will iterate 2 times
3th iteration of outer loop : inner loop will iterate 2 times
4th iteration of outer loop : inner loop will iterate 1 times
5th iteration of outer loop : inner loop will iterate 1 times
6th iteration of outer loop : inner loop will iterate 1 times
7th iteration of outer loop : inner loop will iterate 1 times
8th iteration of outer loop : inner loop will iterate 1 times
9th iteration of outer loop : inner loop will iterate 1 times
10th iteration of outer loop : inner loop will iterate 1 times
TOTAL COUNT is : 14
Upvotes: 0