Order of growth in two loops - java

What is the order of growth in the following code?
int result = 0;
for (int i = 1; i <= n; i *= 2)
for (int j = 0; j <= i; j++)
result++;
The answer is supposed to be n, but I'm not sure how to figure that out.
How can I calculate the order of growth in these loops?
My assumption would be that the outer loop runs (log n + 1) times. The inner loop is dependant of the outer loop, since it uses i. But how is this equal to n?

Each time the inner loop executes for a given i, it has i+1 iterations.
Since i has the values 2^0, 2^1, 2^2, 2^3, 2^4, ...
The total number of iterations of all the executions of the inner loop is bound by
2^0 + 1 + 2^1 + 1 + 2^2 + 1 + ... + 2^k + 1 where 2^k <= n
that's bound by
2^0 + 2^1 + ... + 2^k + logn
Now we have the sum of a geometric series:
2^0 + 2^1 + ... + 2^k = 2^(k+1) - 1 <= 2n - 1 since 2^k <= n
Therefore you get a bound of:
2n - 1 + logn
which is O(n).

Related

What is supposed to be the Time Complexity of this loop

What should be the time complexity of this code?
I am thinking (n^2 -n) as the loop will run n(n-1)/2 times.
for (int i = 0; i < n-1; i++) {
for (int j = i + 1; j < n; j++) {
System.out.println(i + "i " + j + " j");
}
}
i: outer loop runs n - 1 times
j: inner loop runs n - (i + 1) times
Analyze it with a small number, say n = 10.
The outer loop will run 9 times.
The inner loop will run as follows
i = 0: 9 times
i = 1: 8 times
i = 2: 7 times
...
i = 8: 1 time
Therefore
n * ( n - 1) = n ^ 2 - n
For very large values of n, n is insignificant when compared to n squared.
See also wikipedia asymtotic analysis.

Time complexity and Gauss Sum Identity in Java Nested Loops

public static int[] intSum(int[] arr2) {
int[] arr1 = new int[arr2.length];
for (int i = 0; i < arr2.length; i++) {
for (int j = 0; j <= i; j++) {
arr1[i] += arr2[j];
}
}
return arr1;
}
Given the method, we were told that the inner loop can be summarized using Gauss's sum identity, and as such, the complexity in polynomial form is
T(n) = c_0 + c_1 * n + c_2 * n + (1 + 2 + ... + (n-1)) * c_3
=> T(n) = c_0 + n * c_1 * n * c_2 * (n(n+1))/2 * c_3
I don't really understand this calculation. I get that c_1 * n is the array initialization which is O(n) in Java, and that c_2 * n would be the outer loop, but how does the sum up from 1 to n-1 work here and how is that related to the inner loop?
Ignoring the syntax errors in your code snippet, the inner loop runs from 0 to i, where i increases each time the for is executed again. This gives the sum 0 + 1 + 2 + ... + n.
Now this sum was calculated by the young Gauss in the following way (for even n, but a similar construction works for odd n):
1 + n = n+1
2 + (n-1) = n+1
3 + (n-2) = n+1
...
n/2 + n/2+1 = n+1
So in total there are n/2 lines with a sum of n+1 each. This gives the result n*(n+1)/2

Find complexity of algorithm using step count

First of all - yes, I have read several posts here on SO, as well as other places about estimating the complexity of an algorithm.
I have read this, this and this, as well as others
I want to try with an algorithm I wrote that finds the largest rectangle, to see if I understood anything at all from what I've read.
public static long getLargestRectangle(long[] arr, int index, long max) {
int count = 1; //1 step * 1
int i = index - 1; //1 step * 1
int j = index + 1; //1 step * 1
if(index == arr.length-1) return max; //1 step * 2
while(i > -1 && arr[index] <= arr[i]) { //1 step * (N+1)
count++; //1 step * N
i--; //1 step * N
}
while(j <= arr.length-1 && arr[index] <= arr[j]) { //1 step * (N+1)
count++; //1 step * N
j++; //1 step * N
}
max = (max < (arr[index] * count) ? (arr[index] * count) : max); //1 step * 7
return getLargestRectangle(arr, index + 1, max); //1 step * 1
}
//total number of steps: 1 + 1 + 1 + (N + 1) + N + N + (N + 1) + N + N + 7
//=> 6N + 12 = O(N) ?
Am I way off here? I'd love some insight.
EDIT
Like this?
T(n) = O(N) + T(n+1)
T(n) = O(N) + O(N) + T(n+2)
T(n) = O(N) + O(N) + O(N) + T(n+3)
T(n) = i * O(N) + (n+i)
T(n) = n * O(N) + (n+n)
= O(N^2)
If this is wrong, I'd really appreciate if you could update your answer and show me.
Am I way off here? I'd love some insight.
I am afraid so :(
return getLargestRectangle(arr, index + 1, max); //1 step * 1
This above is NOT 1 step, it is a recursive invokation of the method. This method "shrinks" the array by 1 element, so this step actually costs T(n-1), where T(.) is the time complexity of the algorithm.
Combining this with what you already have, you get
T(n) = T(n-1) + O(N)
Solving this recurrence formula will give you the algorithm's complexity.
Note: T(n) = T(n-1) + O(N) is a syntatic sugar, it should actually have been T(n) <= T(n-1) + CONST*N for some constant CONST, since you cannot add a set (O(N)) to a scalar (T(n-1)).
Also note: N!=n. n changes over time, N is the initial length of the array. It is so because your algorithm is actually traversing from n (index) to 0, and from n to N.
This does not change the time complexity in terms of big O notation, however.

complexity of two dependent for loops with outer loop of log n complexity

The problem
Compute the complexity of this algorithm:
for(i=n; i>1;i=i/2)
for(j=i;j<n;j++){
statement;
}
What have I done on this topic before:
The first loop runs logn times.
The second loop runs n-i times with i starting from n and changing to i/2 in each outer loop iteration. So the inner loop runs like this:
n-n 0 times
n - n/2 n/2 times
n - n/4 3n/4 times
n - n/8 7n/8 times
n - n/16 15n/16 times
and so on till
n - 1 times
so the general term is n * ((2^n)-1)/(2^n)
Now this sequence is not arithmetic nor geometric. So formula of n/2 * (a+l) cannot be applied on it. How do I further proceed with this solution or if it is wrong, then what is the correct method.
Note: If n/2*(a+l) is applied, the resulting complexity is -n/(2^n) = O(2^n).
You are on the right track. As you mentioned, the inner loop would run log n times. So, the total number of times it runs is:
(n - n/2) + (n - n/4) + ... (log n) times
= n*(log n) - (n/2 + n/4 + n/8 + ... up to 1)
= n*(log n) - n*(1/2 + 1/4 + ...)
<= n*(log n) - n because (1/2 + 1/4 + ...) is 1 even if we take all terms till infinity (G.P)
= n(log n - 1), which is O(n*log(n))
Remember that when calculating complexity, you are always looking for upper bounds, not exact numbers.
First the calculations
A := (n - n) + (n - n/2) + (n - n/4) + ... + (n - n / 2^logn) =
log n * (n) - n * (1 + 1/2 + 1/4 + 1/8 + .... 1 / 2 ^ logn)
A > log n * (n) - n * (1 + 1/2 + 1/4 + 1/8 + .... + 1 / 2^infity) =
logn * n - n = n(logn - 2)
A < log n * (n)
As you see I have assigned the expression you want to evaluate to A. From the last two inequations it follows the complexity of your algorithm is thetha(n logn)
Here I used the well known geometric progression of (1 + 1/2 + 1/4 + .....) = 2
The exact no of times the statement runs is
nlogn - 2n(1-1/2^logn)

Determining as a function of n how often the statement incrementing the variable count is performed

Ok so I'm new to analyzing algorithms and would really appreciate any helpful tips that can be shared on how to go about this. I am trying to determine how many times count is incremented as a function of n. I have ran it in an ide and for values 1-7 the output is 1,3,6,10,15,21,28. Im just unsure how to write this as a function of n? Thanks.
The loop is as follows:
for(int i = 1 ; i <= n ; i++){
for (int j = 1 ; j <= i ; j++) {
count++;
}
}
The aim of this type of exercise is to teach how to you analyze it on paper instead of running it on a machine. But let's look at the pattern:
The outer loop will run a total of n times
The inner loop will run between 1 to n times depend on what i is at the time. But you know that on average this will run (n+1)/2 times.
Thus count = n(n+1)/2), which is O(n^2)
See arithmetic series
Update: As requested - why the inner loop is (n+1)/2:
The outer loop will increment i between 1 and n. So on each iteration of the outer loop, the inner loop will "loop" one more than than it did previously.
Thus the inner loop will iterate this number of times:
1 + 2 + 3 + ... + n
So we can do something clever and pair up :
n with 1: (n + 1) = n + 1
n-1 with 2: (n - 1) + 2 = n + 1
n-2 with 3: (n - 2) + 3 = n + 1
...
And since we paired these up, we have n/2 such pairs:
So the sum of 1 + 2 + ... + n is ( (n+1) * (n/2) ).
So the average is ( (n+1) * (n/2) ) / n = (n+1)/2
(Visualize it as you are writing 1 + 2 + 3 + ... + n on a long strip of paper, and you fold it in half.)
I would also highly recommend reading this famous story about Karl Friedrich Gauss so you'll always remember how to sum arithmetic series =)
1
1+2 = 3
1+2+3 = 6
1+2+3+4 = 10
1+2+3+4+5 = 15
It is only me who sees the pattern? :-)
Here you go:
count = n * (n + 1) / 2

Categories