I'm trying to find the time complexity of the following function:
for (int i = 0; i < arraySize; i++) {
for (int j = 0; j < arraySize; j++) {
if (array[j] < array[i]) {
//Do something
}
else if (array[j] == array[i]) {
//Do something else
}
}
}
I think it is O(n^2), but I'm not sure how to prove it.
You are correct. It is O(n^2).
Rule of thumb: Simple programs can be analyzed by counting the nested loops of the program. A single loop over n items yields f( n ) = n. A loop within a loop yields f( n ) = n^2. A loop within a loop within a loop yields f( n ) = n^3.
You can also check with the link below for,
How to find time complexity of an algorithm
Hope this helps!
Related
double A[N] = { ... }, B[N] = { ... };
for (int i = 1; i < N; i++) {
A[i] = B[i] – A[i –1];
}
Why can't this loop be parallelized using the #pragma omp parallel for construct?
The reason is pretty plain in the code. To calculate A[i] you need to calculate A[i-1] first. There are N steps where every step depends on the previous step.
In general, a loop for(int i=1; i<N; i++) is suitable for parallelism if the loop would produce the exact same result if you changed the header to for(int i=N-1; i>0; i--)
Maybe that was a bit confusing. It has nothing to do with reverse order. The point is that you should be able to do each step individually.
in regarding to my previous post: Complexity to find if there is a missing element in an array --> i am trying to solve an algorithm to check if an array has all elements between 0 and n - 1 in the most efficient way (time complexity wise) without an extra array,. i came up with two solutions. could you help me determine which one is more efficient? which one should i turn in? thank you.
/* first attempt */
int check_missing_a(int *a, int n)
{
int i, flag = 0;
for (i = 0; i < n; i++)
{
if (a[i] < 0 || a[i] >= n) //check for unwanted integers
return 0;
while (i != a[i])
{
swap(&a[a[i]], &a[i]); //puts numbers in their index
flag++;
if (flag > 1 && a[i] == a[a[i]]) //check for duplicates
return 0;
}
flag = 0;
}
return 1;
}
/* second attempt */
int check_missing_b(int *a, int n)
{
int i, sum_a = 0, sum_i = 0, sum_aa = 0, sum_ii = 0;
for (i = 0; i < n; i++)
{
if (a[i] < 0 || a[i] >= n) //check for unwanted integers
return 0;
else
{
sum_a += a[i]; // sum of 'elements' should be equal to sum of 'i'
sum_i += i;
sum_aa += a[i] * a[i]; // multiplication sum of 'elements' should be equal to multiplication sum of 'i'
sum_ii += i * i;
}
}
return (sum_aa == sum_ii && sum_a == sum_i);
}
First of all, we need to fix check_missing_a because it's buggy. After the swap, a[i] might be out of bounds for following a[a[i]]. Fixed version:
int check_missing_a2(int *a, int n) {
for (int i = 0; i < n; ++i) {
while (i != a[i]) {
if (a[i] < i || a[i] >= n || a[i] == a[a[i]])
return 0;
swap(&a[i], &a[a[i]]);
}
}
return 1;
}
We can even save a few comparisons as follows: (Thanks to #chmike)
int check_missing_a2(int *a, int n)
{
for (int i = 0; i < n; ++i)
if (a[i] < 0 || a[i] >= n)
return 0;
for (int i = 0; i < n; ++i) {
while (i != a[i]) {
if (a[i] == a[a[i]])
return 0;
swap(&a[i], &a[a[i]]);
}
}
return 1;
}
Complexity of check_missing_a2
At first glance, one might think that check_missing_a2 is slower than O(N) because the outer loop does N passes and there's another inner loop.
However, the inner loop performs at most N-1 swaps. For example, the following illustrates the number of swaps for each arrangement of the numbers in 0..N-1 for N=8:
# swaps # arrangements
------- --------------
0 1
1 28
2 322
3 1960
4 6769
5 13132
6 13068
7 5040
As #4386427 explained, every swap places at least one element in its correct position. Consequently there can't be more than N swaps.
This means that no part of the function is executed more than 2*N times, for a resulting complexity of O(N).
Complexity of check_missing_b
A single loop with N passes, for a complexity of O(N).
As for actual performance, I suspect that check_missing_a2 will always be faster than check_missing_b.
Of course, there's also the issue that check_missing_a2 changes the array and that check_missing_b could overflow.
Function check_missing_b is definitely O(n) because it has only one loop. It also has the property to not modify the input array a. However, it has a limitation in the magnitude of n because sum_ii might overflow.
Function check_missing_a has two loops and is less obvious to analyze. It also sort the values in the array a and thus modify the input array. This might be a problem. On the other hand it is not subject to overflow which is an advantage over the other function.
This function is a radix sort because each swap puts a value in its final place. There will be less than n swaps. This function is thus O(n).
Unfortunately, this function has also a problem. A value a[a[i]] may be bigger than n when a[i] > i. The function requires thus two pass on the elements. A first pass, ensures that no value is smaller than 0 and bigger than n-1. A second pass does the radix sort.
Here is my suggested implementation of the function check_missing_a.
int check_missing_c(int *a, int n)
{
for (int i = 0; i < n; i++)
if (a[i] < 0 || a[i] >= n)
return 0;
for (int i = 0; i < n; i++)
while (i != a[i]) {
if (a[i] == a[a[i]])
return 0;
int tmp = a[i];
a[i] = a[tmp];
a[tmp] = tmp;
}
return 1;
}
#include <stdio.h>
int f(int (*d)[2], int n)
{
int p = 0, cnt;
for (int i=2; i*i <= n; ++i)
{
for (cnt = 0; n % i == 0; cnt++, n /= i) {}
if (cnt == 0)
continue;
d[p][0] = i;
d[p++][1] = cnt;
}
if (n > 1)
{
d[p][0] = n;
d[p++](l] = 1;
}
return p;
}
So as far as I understand when I m looking for complexity, I m looking for loops. The first loop is trivial. It gives us O(sqrt(n)), but there is a second loop which decreases n, I don t really understand this moment. Experiments show that complexity is O(log(n)).
Speaking of the second loop : n % i == 0; and n=n/i; if we loop in the for loop we will have in the first iteration n=n/i/i .... in the k iteration we are going to have n/(i^k) and this will stop when n%i!=0; lets say n/(i^k)==1 so 1%i==1 !=0 so from n/(i^k)==1 we are going to have k=log(n) in i base which mean log(n)
Nested loop logic to skip the inner loop when its index equals the outer loop index.
Used an if statement within the inner loop to the effect of:
for (i=0;i<N;i++)
for (j=0;j<N;j++)
if (j!=i)
... some code
I believe this gives me the expected results but is there a less CPU consuming method that I may not be aware of?
If you can assume that N <= i, you can split the inner loop into 2 separate for loops to reduce the number of tests:
for (i = 0; i < N; i++) {
for (j = 0; j < i; j++) {
... some code
}
/* here we have j == i, skip this one */
j++;
for (; j < N; j++) {
... same code
}
}
This results in more code but half as many tests on j. Note however that if N is a constant, the compiler might unroll the original inner loop more efficiently. Careful benchmarking is the only way to determine if this solution is worth the effort for your problem, compiler and architecture.
For completeness, this code can be simplified as:
for (i = 0; i < N; i++) {
for (j = 0; j < i; j++) {
... some code
}
/* here we have j == i, skip this one */
while (++j < N) {
... same code
}
}
void fun(int n, int arr[])
{
int i = 0, j = 0;
for(; i < n; ++i)
while(j < n && arr[i] < arr[j])
j++;
}
The answer given is: variable j is not initialized for each value of variable i, so time complexity is O(n)
I don't quite understand it. Can anyone explain?
See the difference between your function and this (this is in O(n2) time complexity) -
void fun(int n, int arr[])
{
int i = 0, j = 0;
for(; i < n; ++i)
{
j = 0;
while(j < n && arr[i] < arr[j])
j++;
}
}
In your function the variable j is not initialized for each value of variable i. So, the inner loop runs at most n times.
Edit 1- From j=0 to j=n is maximum n iterations of inner while loop. Since you never initialize j again once j=n the inner while loop will never iterate. So at maximum (it could be less depending on the second condition arr[i] < arr[j]) you have n iterations of inner while loop once. The outer for loop will obviously iterate n times . So you have n+n=2n and not n2 even in the worst case.
Edit 2- #Kerrek SB answer to this is spot-on -
"The code finishes when j has been incremented n times. j never gets decremented, and at most n attempts are made at incrementing it (via i)"
The outer loop is executed n times.
The inner loop only continues if j < n, and since j is incremented in each step, it cannot be executed more than n times in total.