Example. Analysing the Run-Time Complexity of a Function
[comp1110-7S]
Based on our simple rules, we now work an example of analysing the complexity of the following function in terms of the size of the given array:
int determineComplexity(int[] numbers) {
int n=numbers.length;
int result=0;
for (int i=0; i<n; i++) {
for (int j=i+1; j<n; j++) {
if (numbers[i]==numbers[j]) {
result++;
}
}
}
for (int i=0; i<n; i++) {
for (int j=Math.max(i-1,0); j<Math.min(i+2,n); j++) {
result = result + numbers[i][j];
}
}
return result;
}
This function contains two pairs of nested loops, and each loop mentions the variable n, which conveniently is the size of the given array.
We'll start by looking at the first innermost loop:
for (int j=i+1; j<n; j++) {
if (numbers[i]==numbers[j]) {
result++;
}
}
Array accesses and increasing the value of result are constant operations, so is checking a boolean in an if-condition.
That is, the body of the loop has time complexity \(O(1)\).
The loop itself starts from some value between 0 and n and goes up to n, without any constant limit as to how far away from n the start might be, and as such executes \(O(n)\) times.
Therefore, the overall time complexity of this loop is \(O(n * 1) = O(n)\).
We can now look at it's parent loop, having collapsed its inner loop:
for (int i=0; i<n; i++) {
//O(n)-cost operation here
}
This loop clearly executes n times, each with an \(O(n)\)-cost operation inside. As such, the total time complexity of this outer loop is \(O(n * n) = O(n^2)\).
Moving on to the second inner loop:
for (int j=Math.max(i-1,0); j<Math.min(i+2,n); j++) {
result = result + numbers[i][j];
}
This one is more interesting. The inside of the loop again has a constant cost. But how often does the loop iterate? We start from the maximum of 0 and i-1, and go up to the minimum of i+2 and n.
Let's consider the cases:
- If
i-1 is less than 0, we start from 0. Then:
- If
i+2 is less than n, we go up to i+2. Since i-1 is less than 0, i is at most 0, and therefore i+2 is at most 2. This means that the loop does at most 2 iterations, which is a constant.
- Otherwise,
n is less than or equal to i+2, which we already established is at most 2, and we again end up with at most 2, and therefore a constant number of, iterations.
- If
i-1 is greater than or equal to 0, we start from i-1. Then:
- If
i+2 is less than n, we go up to i+2. Since i-1 is 3 less than i+2, the loop does 3 iterations, which is a constant.
- Otherwise,
n is less than or equal to i+2, which we already established is 3 more than the starting point. We again end up with at most 3, and therefore a constant number of, iterations.
A constant number of iterations over a constant-cost operation means the total time complexity for the inner loop here is \(O(1 * 1) = O(1)\). Now for the parent loop:
for (int i=0; i<n; i++) {
//O(1)-cost operation here
}
This loop clearly executes n times, each with an \(O(1)\)-cost operation inside. As such, the total time complexity of this outer loop is \(O(n * 1) = O(n)\).
Having collapsed all our loops, we have:
int determineComplexity(int[] numbers) {
int n=numbers.length;
int result=0;
//O(n)-cost operation here
//O(1)-cost operation here
return result;
}
The time complexity of this function is therefore: \(O(n + 1) = O(n)\), i.e. linear.