Algorithm Complexity Analysis Confusion - java

static int sumAfterPos(int[] A) {
int N = A.length;
for (int i = 0; i < N; i += 1) {
if (A[i] > 0) {
int S;
S = 0;
for (int j = i + 1; j < N; j += 1) {
S += A[j];
}
return S;
}
}
return 0;
}
I am having trouble figuring out whether this code runs in O(n^2) or in O(n). I am not sure whether the return S will have a big impact on the runtime.

It is O(N) in time.
For example, A[K] > 0, then you have already have K steps. Then you run another N-K steps and return. So totally you have O(N).
Let us say, all A[i] < 0, this will make the inner loop away. So it is O(N) in this case.
Now let us say, A[0] > 0, this will make the out loop only repeat once and the inner loop will run from 1 to N - 1, so totally you have 1 + (N-1 - 1 + 1) = N.
Now let us say, A[1] > 0, this will make the out loop only repeat twice and the inner loop will run from 2 to N - 1, so totally you have 2 + (N-1 - 2 + 1) = N.
...
Now let us say, A[k] > 0, this will make the out loop only repeat k + 1 times and the inner loop will run from k + 1 to N - 1, so totally you have k + 1 + (N-1 - k -1 + 1) = N.
Now let us say, A[N-1] > 0, this will make the out loop only repeat N and the inner loop will never run, so totally you have N times.

This looks to be O(n), or rather, exactly N iterations will occur. If the statement (A[i] > 0) is true, then a value would be returned after the inner for loop completes its iterations. If there are N elements in the array A, and the outer for loop is at iteration i, and the conditional is met, then the inner for loop will iterate at most N-i times and then return. If the conditional is never met, then the outer for loop will iterate N times. Thus, exactly N iterations between the outer- and inner- for loops will execute.
Return statements are generally never taken into account in determining the runtime complexity of an algorithm (unless the return statement for some reason is non-trivially complex (eg recursion)).
EDIT: For another perspective, note that as the index i increases linearly, the starting point for the index j increases linearly at the same rate, and thus the possible remaining work is decreasing linearly at the same rate as well. Since the the function is guaranteed to return once the inner loop is reached, the total number of iterations between the two for loops is i+j=N by the end of execution.

Related

Maximum number of times this loop executes

I have this for loop and I am preparing for an exam. I want to see how many times this loop executes.
without knowing the value of K and somevalue, how can we determine the number of times SMALL is printed. The book answer says it is K-1.
for(int i=2; i<= k; i++)
if(arr[i]< someValue)
System.out.println("SMALL");
If it were simply
for (int i = 0; i < k; i++) {
The loop would run k times since you are starting at 0 but not reaching k
So add 2 to the starting point you get k-2 times
add back in 1 because it is <= and you get k-1 times.
It tends to get a little less obvious when the increment isn't 1
Note: That is how many times the loop will execute. The number of times SMALL will print can't be determined without more information.
in this case somevalue doesn't matter, you can calculate the count of executed loop your self by using another variable, use this:
int count = 0;
for (int i = 2; i <= k; i++) {
if (arr[i] < someValue) {
System.out.println("SMALL");
}
count++;
}
System.out.println("this for loop executed: " + count + " times.");
The question needs more inputs because without the values of arr[] and somevalue, we cannot find the answer.
However, since the loop starts at 2 and runs till its equal to k, we can say that it will run till k times -1 (since loop starts 2 for a <= condition instead of the usual 1), which translates to k-1 executions of the loop.
Still it doesn't guarantee the number of times "SMALL" will be printed. That is only possible if all values in the array arr are less than somevalue

What is the running time of this Triple nested for loop?

Here is the code:
for (int i = 0; i < 60; i++) {
for (int j = i-1; j < N; j++) {
for (int k = 0; k+2 < N; k++) {
System.out.println(i*j);
System.out.println(i);
i=i+1;
}
}
}
I believe it is O(N^2) since there's two N's in the for loops, but not too sure.
Any help is appreciated, thanks!
It's rather because the i-loop has a fixed limit. Saying it's O(N^2) is not wrong IMO but if we are strict, then the complexity is O(N^2 * log(N)).
We can prove it more formally:
First, let's get rid of the i-loop for the analysis. The value of i is incremented within the k-loop. When N is large, then i will get larger than 60 right in the first iteration, so the i-loop will execute just one iteration. For simplicity, let's say i is just a variable initialized with 0. Now the code is:
int i = 0;
for (int j = -1; j < N; j++) { // j from - 1 to N - 1
for (int k = 0; k+2 < N; k++) { // k from 0 to N - 1 - 2
System.out.println(i*j);
System.out.println(i);
i=i+1;
}
}
If we are very strict then we'd have to look at different cases where the i-loop executes more than one time, but only when N is small, which is not what we are interested in for big O. Let's just forget about the i-loop for simplicity.
We look at the loops first and say that the inner statements are constant for that. We look at them separately.
We can see that the complexity of the loops is O(N^2).
Now the statements: The interesting ones are the printing statements. Printing a number is obviously done digit by digit (simply speaking), so it's not constant. The amount of digits of a number grows logarithmic with the number. See this for details. The last statement is just constant.
Now we need to look at the numbers (roughly). The value of i grows up to N * N. The value of j grows up to N. So the first print prints a number that grows up to N * N * N. The second print prints a number that grows up to N * N. So the inner body has the complexity O(log(N^3) + log(N^2)), which is just O(3log(N) + 2log(N)), which is just O(5log(N)). Constant factors are dropped in big O so the final complexity is O(log(N)).
Combining the complexity of the loops and the complexity of the executed body yields the overall complexity: O(N^2 * log(N)).
Ask your teacher if the printing statements were supposed to be considered.
The answer is O(N^2 log N).
First of all, the outer loop can be ignored, since it has a constant number of iterations, and hence only contributes by a constant factor. Also, the i = i+1 has no effect on the time complexity since it only manipulates the outer loop.
The println(i * j) statement has a time complexity of O(bitlength(i * j)), which is bounded by O(bitlength(N^2)) = O(log N^2) = O(log N) (and similarly for the other println-statement. Now, how often are these println-statement executed?
The two inner loops are nested and and both run from a constant up to something that is linear in N, so they iterate O(N^2) times. Hence the total time complexity is O(N^2 log N).

What will be the time complexity of the below code? [duplicate]

This question already has answers here:
How can I find the time complexity of an algorithm?
(10 answers)
Closed 2 years ago.
I have the below code to return the index of 2 numbers that add up to the given target. What is the time complexity of the code? Explanations are appreciated. Thanks.
int[] result = new int[2];
int i=0, k=i+1;
while (i < nums.length)
{
if(nums[i]+nums[k]==target && i!=k)
{
result[0]=i;
result[1]=k;
break;
}
else if (k < nums.length-1)
k++;
else
{
i++;
k=i;
}
}
return result;
Premise
It is hard to analyze this without any additional input how nums and target correspond to each other.
Since you do not provide any additional information here, I have to assume that all inputs are possible. In which case the worst case is that none of the pairs buildable by nums can form target at all.
A simple example explaining what I am referring to would be target = 2 with nums = [4, 5, 10, 3, 9]. You can not build target by adding up pairs of nums.
Iterations
So you would end up never hitting your break statement, going through the full execution of the algorithm.
That is, the full range of k from 0 to nums.length - 1, then one increment of i and then k again the full range, starting from i. And so on until i reaches the end as well.
In total, you will thus have the following amount of iterations (where n denotes nums.length):
n, n - 1, n - 2, n - 3, ..., 2, 1
Summed up, those are exactly
(n^2 + n) / 2
iterations.
Complexity
Since all you do inside the iterations is in constant time O(1), the Big-O complexity of your algorithm is given by
(n^2 + n) / 2 <= n^2 + n <= n^2 + n^2 <= 2n^2
Which by definition is in O(n^2).
Alternative code
Your code is very hard to read and a rather unusual way to express what you are doing here (namely forming all pairs, leaving out duplicates). I would suggest rewriting your code like that:
for (int i = 0; i < nums.length; i++) {
for (int j = i; j < nums.length; j++) {
int first = nums[i];
int second = nums[j];
if (first + second == target) {
return {i, j};
}
}
}
return null;
Also, do yourself a favor and do not return result filled with 0 in case you did not find any hit. Either return null as shown or use Optional, for example:
return Optional.of(...);
...
return Optional.empty();
Time Complexity
The worst-case time complexity of the given code would be O(N^2) , where N is nums.length.
This is because you are checking each distinct pair in the array until you find two numbers that add upto the target. In the worst case, you will end up checking all the pairs. The number of pairs in an array of length N would be N^2. Your algorithm will check for N*(N-1) pairs which comes out to be N^2 - N. The upper bound for this would be O(N^2) only since lower order terms are neglected.
Flow of Code
In the code sample, here's how the flow occurs -
i will start from 0 and k will be i+1 which is 1. So, suppose that you won't find the pair which add up to the target.
In that case, each time ( from i = 0 to i = nums.length-1), only the else if (k < nums.length-1) statement will run.
Once k reaches nums.length, i will be incremented and k will again start from i+1.
This will continue till i becomes nums.length - 1. In this iteration the last pair will be checked and then only the loop will end. So worst-case time complexity will come out to be O(N^2) .
Time Complexity Analysis -
So you are checking N pairs in the first loop, N-1 pairs in the next one, N-2 in next and so on... So, total number of checked pairs will be -
N + ( N-1 ) + ( N-2 ) + ( N-3 ) + ... + 2 + 1
= N * ( N + 1 ) / 2
= ( N^2 + N ) / 2
And the above would be considered to have an upper bound of O(N^2) which is your Big-O Worst-Case time complexity.
The Average Case Time Complexity would also be considered as O(N^2).
The Best Case Time Complexity would come out to be O(1) , where only the first pair would be needed to be checked.
Hope this helps !

Do I have the right approach to finding the asymptotic complexity of the following Java functions?

Example1:
This I would say is O(log(n)), my reasoning is that if we choose a test n, n = 10, then 'i' would run: 0,2,4,6,8,10, so 'i' is behaving linearly not growing but just adding + 2 each time it iterates. And the method is also 'n' - dependent meaning that as n grows so does the method. So the first loop is O(n), then the second loop goes, if we choose n test to be n = 10, then after each iteration 'j' would run: 2,4,8,16,32,64 then can be thought of as 2^n which is a logarithmic function, so this loop is logarithmic. So computing this: O(n)*O(log(n)) = O(log(n))
for (i = 0; i < n; i = i + 2) {
for ( i = 1; j <= n; j = j*2) {
System.out.println("Hi");
}
}
Example2:
for this one if we choose n to be n = 10, then 'i' runs: 2,4,8,16,32 again can be rewritten as 2^n, this is logarithmic, O(log(n))
for (i = 1; i < n; i = i + i) {
System.out.println("Soda");
}
Example3:
for this one the first loop is n-dependent, the method changes as n grows, nothing fancy with 'i' it simply adds +1 so this is a n-dependent loop of O(n) for any inputted n.
if the number is even it runs the first nested loop, if the number is positive it runs the second nested loop. The first inner loop is the same complexity, O(n). and the last inner loop is (I think, despite n*n) O(n). So computing this we get: O(n)*O(n) = O(n^2) if the if-statement is true, and O(n)*O(n) if the if statement is false, so in the worst case it is O(n^2) because we multiply the two O(n)'s.
for (i = 0; i < n; i++) {
if (i % 2 == 0) {
for (j = 0; j < n; j++) {
System.out.println("Rawr");
}
} else {
for (j = 0; j < n*n; j++) {
System.out.println("Computer");
}
}
Have I made errors?
please explain
Thank you
Unfortunately, from the info you are giving, not much can be told. Are you looking for time complexity? spacetime complexity? runtime complexity?
In addition to this, the complexity of methods is actually only to be useful if the method is called more than once, which doesn't happen as you propose. If you don't know how the method is called, you will not be able to determine the complexity(either one of them) accurately.

Algorithmic complexity of naive code for processing all consecutive subsequences of a list: n^2 or n^3?

I'm studying for a test and found this question:
I can't really determine the complexity, I figured it's either O(n2) or O(n3) and I'm leaning towards O(n3).
Can someone tell me what it is and why?
My idea that it's O(n2) is because in the j loop, j = i which gives a triangle shape, and then the k loop goes from i + 1 to j, which I think is the other half of the triangle.
public static int what(int[] arr)
{
int m = arr[0];
for (int i=0; i<arr.length; i++)
{
for (int j=i; j<arr.length;j++)
{
int s = arr[i];
for (int k=i+1; k<=j; k++)
s += arr[k];
if (s > m)
m = s;
}
}
return m;
}
Also if you can tell me what it does?
I figured it returns the addition of positive integers or the biggest integer in the array.
But for arrays like {99, -3, 0, 1} it returns 99, which I think is because it's buggy. If not than I have no Idea what it does:
{99, 1} => returns 100
{-1, -2, -3} => return -1
{-1, 5, -2} => returns 5
{99, -3, 0, 1} => returns 99 ???
You can proceed methodically, using Sigma Notation, to obtain the order of growth complexity:
You have 3 for statements. For large n, it is quite obvious that is O(n^3). i and j have O(n) each, k is a little shorter, but still O(n).
The algorithm returns the biggest sum of consecutive terms. That's why for the last one it returns 99, even if you have 0 and 1, you also have -3 that will drop your sum to a maximum 97.
PS: Triangle shape means 1 + 2 + ... + n = n(n+1) / 2 = O(n^2)
Code:
for (int i=0; i<arr.length; i++) // Loop A
{
for (int j=i; j<arr.length;j++) // Loop B
{
for (int k=i+1; k<=j; k++) // Loop C
{
// ..
}
}
}
Asymptotic Analysis on Big-O:
Loop A: Time = 1 + 1 + 1 + .. 1 (n times) = n
Loop B+C: Time = 1 + 2 + 3 + .. + m = m(m+1)/2
Time = SUM { m(m+1)/2 | m in (n,0] }
Time < n * (n(n+1)/2) = 1/2 n^2 * (n+1) = 1/2 n^3 + 1/2 n^2
Time ~ O(n^3)
No matter triangle shape or not, it always a complexity O(N^3), but of course with lower constant then a full triple nested cycles.
You can model the running time of the function as
sum(sum(sum(Theta(1), k=i+1..j),j=i..n),i=1..n)
As
sum(sum(sum(1, k=i+1..j),j=i..n),i=1..n) = 1/6 n^3 - 1/6 n,
the running time is Theta(n^3).
If you do not feel well-versed enough in the underlying theory to directly apply #MohamedEnnahdiElIdri's analysis, why not simply start by testing the code?
Note first that the loop boundaries only depend on the array's length, not its content, so regarding the time complexity, it does not matter what the algorithm does. You might as well analyse the time complexity of
public static long countwhat(int length) {
long count = 0;
for (int i = 0; i < length; i++) {
for (int j = i; j < length; j++) {
for (int k = i + 1; k <= j; k++) {
count++;
}
}
}
return count;
}
Looking at this, is it easier to derive a hypothesis? If not, simply test whether the return value is proportional to length squared or length cubed...
public static void main(String[] args) {
for (int l = 1; l <= 10000; l *= 2) {
long count = countwhat(l);
System.out.println("i=" + l + ", #iterations:" + count +
", #it/n²:" + (double) count / l / l +
", #it/n³:" + (double) count / l / l / l);
}
}
... and notice how one value does not approach anyconstant with rising l and the other one does (not incidentally the very same constant associated with the highest power of $n$ in the methodological analysis).
This requires O(n^3) time due to the fact that in the three loops, three distinct variables are incremented. That is, when one inside loop is over, it does not affect the outer loop. The outer loop runs as many times it was to run before the inner loop was entered.
And this is the maximum contiguous subarray sum problem. Self-explanatory when you see the example:
{99, 1} => returns 100
{-1, -2, -3} => return -1
{-1, 5, -2} => returns 5
{99, -3, 0, 1} => returns 99
There is an excellent algorithm known as Kadane's algorithm (do google for it) which solves this in O(n) time.
Here it goes:
Initialize:
max_so_far = 0
max_ending_here = 0
Loop for each element of the array
(a) max_ending_here = max_ending_here + a[i]
(b) if(max_ending_here < 0)
max_ending_here = 0
(c) if(max_so_far < max_ending_here)
max_so_far = max_ending_here
return max_so_far
References: 1, 2, 3.
O(n^3).
You have calculated any two item between arr[0] and arr[arr.length - 1], running by "i" and "j", which means C(n,2), that is n*(n + 1)/2 times calculation.
And the average step between each calculation running by "k" is (0 + arr.length)/2, so the total calculation times is C(n, 2) * arr.length / 2 = n * n *(n + 1) / 4, that is O(n^3).
The complete reasoning is as follows:
Let n be the length of the array.
1) There are three nested loops.
2) The innermost loop performs exactly j-i iterations (k running from i+1 to j inclusive). There is no premature exit from this loop.
3) The middle loop performs exactly n-j iterations (j running from i to n-1 inclusive), each involving j-i innermost iterations, in total (i-i)+(i+1-i)+(i+2-i)+... (n-1-i) = 0+1+2... + (n-1-i). There is no premature exit from this loop.
4) The outermost loop performs exactly n iterations (i running from 0 to n-1 inclusive), each involving 0+1+2+ ... (n-1-i) innermost iterations. In total, (0+1+2... n-1) + (0+1+2+... n-2) + (0+1+2+... n-3) + ... (0). There is no premature exit from this loop.
Now how do handle handle this mess ? You need to know a little about the Faulhaber's formula (http://en.wikipedia.org/wiki/Faulhaber%27s_formula). In a nutshell, it says that the sum of integers up to n is O(n^2); and the sum of the sum of integers up to n is O(n^3), and so on.
If you recall from calculus, the primitive of X is X^2/2; and the primitive of X^2 is X^3/3. Every time the degree increases. This is not by coincidence.
Your code runs in O(n^3).

Categories

Resources