Initialise ARR_SIZE to 1000000 Initialise index_i to 0 Initialise pairCount to 0 Initialise x to 54321 while index_i is less than ARR_SIZE Initialise index_j to index_i+1 while index_j is less than ARR_SIZE if array[index_i]+array[index_j] is less or equal to x Increment pairCount increment index_j endof while increment index_x endof while
At first I said it is $O(n log n)$ but then with the hint the second loop itself average complexity is O(n/2) so overall I said it would be $O(ncdot n/2)$ but in Big $O$ notation it would be $O(n)$ because $n/2$ is a constant(although I was not too sure). So what is the average complexity of this overall algorithm? PS: I know that I could have decreased the complexity by adding an extra else, index_j = ARR_SIZE, which would be $O(N)$ complexity, but I couldn’t think of it during the interview.
Asked By : Sarp Kaya
Answered By : svinja
int count = 0; for (int low = 0, high = list.Count - 1; high >= 1 && low != high; ) { if (list[high] + list[low] <= x) { count += high - low; low++; } else { high--; } }
Regarding constants and complexity Judging by your comment, you are confused about what is ignored and why. First, n/2 is not a constant because it depends on n. As n grows, n/2 grows, so it is clearly not constant. The constant that is ignored in n*n/2 is 1/2, and what remains is n*n. So the complexity is N^2. The actual number of inner loop executions is N^2/2, but this is still O(N^2). The fact you brought up in your comment that the inner loop will run 50 times when 10^2 would indicate 100 times is irrelevant, here’s why: Constants are not meaningful unless they are extremely large (a 2^32 constant because your algorithm tests every 32 bit integer) or you calculate the average case cycle count on a reference architecture. Otherwise, actual speed depends on the language used, on how many instructions each operation actually performs, prediction, caching, pipelining, etc and it is difficult to compare the constants of 2 different algorithms, just outright counting syntactic constructs is very misguided. 2X operations may run faster than X operations if what is being done, how and in which order is different. So until you dig a bit deeper and look into the things I mentioned above, counting operations in a high level language is pure wishful thinking. It is a sign of a questionable CS teaching in my opinion because it teaches a nonsense model of code execution, instead of using a valid one, but on a simple reference architecture (like Knuth does), if you insist on counting operations. Consider these two pieces of code:
for (int j = 0; j < N - 1; j++) for (int i = j + 1; i < N; i++) r += A[i][j];
And:
for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) r += A[i][j];
The first example has N^2 / 2 inner loop repetitions. The second example has N^2 inner loop repetitions. The inner loop body is the same. But the second one is actually much faster on a standard computer (in fact, a smart compiler with certain settings might rewrite your code if you write the first one – so if you test this, turn off optimization)! This is because the second one has much better memory access locality – it accesses the memory locations in order, while the first one jumps around. This causes a much bigger difference in speed than running the loop twice as many times does. And this is just one of many things which affect run speed and are not immediately visible in the code. Second example, two pieces of code:
for (int i = 0; i < N - 1; i++) { for (int j = i + 1; j < N; j++) { int a = A[i][j] * 3; a += 5; r += a; } }
And:
for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) r += A[i][j];
Can you tell me which one has a bigger “constant”? Again, the first inner loop runs 1/2 as many times as the second one. But the first one has 3 lines of code inside the inner loop, while the second one has just one. On my machine, the first one is faster. By what factor? I have no idea (I could measure it, but I can’t tell you by looking at the code). If you decide on a constant A for the first and B for the second program by looking at the code, A/B will probably not be anything like the ratio of actual execution times, making the constants meaningless. So the 1/2 constant is meaningless. Whether a program runs twice faster than some other program depends on so many things that it is not productive to account for small constants on such a superficial level. By the way, you have a bug in your program. The outer loop condition needs to be less than ARR_SIZE – 1 or you are setting index_j to ARR_SIZE in the last outer iteration, and as your indices are 0-based you are reading from beyond the end of your buffer.
Best Answer from StackOverflow
Question Source : http://cs.stackexchange.com/questions/13302