I'm reading this Big O article (and some other book references) trying to figure out what changes affect my algorithm.
so given the following O(N^2) code:
bool ContainsDuplicates(String[] strings)
{
for(int i = 0; i < strings.Length; i++)
{
for(int j = 0; j < strings.Length; j++)
{
if(i == j) // Don't compare with self
{
continue;
}
if(strings[i] == strings[j])
{
return true;
}
}
}
return false;
}
I made the following change:
bool ContainsDuplicates(String[] strings)
{
for(int i = 0; i < strings.Length; i++)
{
for(int j = 0; j < strings.Length; j++)
{
if(i != j) // Don't compare with self
{
if(strings[i] == strings[j])
{
return true;
}
}
}
}
return false;
}
Now both IF's are nested and 'continue' is removed. Does this algorithm really became a O(N^2 + 1) ? and why ?
As far as I see the IF check was there before regardless, so initially thought it would still be a O(N^2).
Big O is describing how execution time grows as a chosen parameter becomes large.
In your example, if we wanted to be exact, the formula would be:
Time taken = Time(start) + Time(external loop) * N + Time (continue) * N + Time (no continue) * N^2
Which can be rewritten as
Time taken = a + b * N + c * N^2
Now, as N becomes larger and larger, it's clear that overall this will be shaped like a parabola. The order zero and order one terms become irrelevant as N grows to infinity.
Time taken (large N) ~= c * N^2
Finally, since we are interested in discussing qualitatively and not quantitatively, we simply describe the algorirhm as N^2
O(N^2) means that the algorithm will behave approximately as c * N^2 for large values of N
It is a similar concept to o(x) in calculus (with the difference that small-o is for parameters going to zero.
Related
I want to understand the time complexity of my below algorithm, which is an acceptable answer for the famous first missing integer problem:
public int firstMissingPositive(int[] A) {
int l = A.length;
int i = 0;
while (i < l) {
int j = A[i];
while (j > 0 && j <= l) {
int k = A[j - 1];
A[j - 1] = Integer.MAX_VALUE;
j = k;
}
i++;
}
for (i = 0; i < l; i++) {
if (A[i] != Integer.MAX_VALUE)
break;
}
return i + 1;
}
Observations and findings:
Looking at the loop structure I thought that the complexity should be more than n as I may visit every element more than twice in some cases. But to my surprise, the solution got accepted. I am not able to understand the complexity.
You are probably looking at the nested loops and thinking O(N2), but it's not that simple.
Every iteration of the inner loop changes an item in A to Integer.MAX_VALUE, and there are only N items, so there cannot be more than N iterations of the inner loop in total.
The total time is therefore O(N).
I'd be very grateful if someone explained to me how to analyse the time complexity of this loop:
int t;
for (i = 1; i <= n; i++){
t = i;
while(t > 0){
t = t/2
}
}
I'm inclined to think that is O(n*log(n)) since it's very similar to:
int t;
for (i = 1; i <= n; i++){
t = n;
while(t > 0){
t = t/2
}
}
but it does less assignments to the variable t. Is this the case?
If it's the case, How could I arrive to this conclusion more rigorously?
For the first snippet, the inner loop runs log(1) + log(2) + ... + log(n) times, which is the same as log(1 * 2 * ... * n) = log(n!) which through Sterling's Approximation is n log(n). Your second snippet has the same complexity. Even if it happens to do less assignments we only care about the overall behavior. In this case both are linearithmic.
Here is the happy number question in leetcode
This is one of the solution
Using Floyd Cycle detection algorithm.
int digitSquareSum(int n) {
int sum = 0, tmp;
while (n) {
tmp = n % 10;
sum += tmp * tmp;
n /= 10;
}
return sum;
}
bool isHappy(int n) {
int slow, fast;
slow = fast = n;
do {
slow = digitSquareSum(slow);
fast = digitSquareSum(fast);
fast = digitSquareSum(fast);
} while(slow != fast);
if (slow == 1) return 1;
else return 0;
}
Is there a chance to have infinite loop?
There would only be an infinite loop if iterating digitSquareSum could grow without bounds. But when it is called with an n digit number the result is always smaller than 100n so this does not happen because for n >= 4 the result is always smaller than the number used as input.
All that ignores that integers in the computer in most languages cannot be arbitrarily large, you would get an integer overflow if the result could grow mathematically to infinity. The result would then be likely wrong but there would still not be an infinite loop.
I believe that the following code is big theta of n^3, is this correct?
for (int i = 0; i < n; i ++)
{ // A is an array of integers
if (A[i] == 0) {
for (int j = 0; j <= i; j++) {
if (A[i] == 0) {
for (int k = 0; k <= j; k++) {
A[i] = 1;
}
}
}
}
}
And that the following is big theta of nlog(n)
for (int i = 1; i < n; i *= 2)
{
func(i);
}
void func(int x) {
if (x <= 1) return;
func(x-1);
}
because the for loop would run log(n) times, and func runs at most n recursive calls.
Thanks for the help!
Your intuition looks correct. Note that for the first bit if the input contains non-zero elements the time complexity drops down to big-theta(n). If you remove the checks it would definitely be big-theta(n^3).
You are correct about the second snippet, however the first is not Big-Theta(n^3). It is not even O(n^3)! The key observation is: for each i, the innermost loop will execute at most once.
Obviously, the worst-case is when the array contains only zeros. However, A[i] will be set to 1 in the first pass of the inner-most loop, and all subsequent checks of if (A[i] == 0) for the same i will be evaluated to false and the innermost loop will not be executed anymore until i increments. Therefore, there are total of 1 + 2 + 3 + .. + n = n * (n + 1) / 2 iterations, so the time complexity of the first snippet is O(n^2).
Hope this helps!
Calculate big o of function. How do I calculate the big O notation in this function?
Example:
function fun1(int n)
{
int s = 0;
for(int i = 0; s < n; i++)
{
s += i;
for(var j = s; j < n; j++)
{
console.log(j);
}
}
return s;
}
Roughly speaking, consider the i-th iteration of the outer loop. After execution of the loop's body,
s = 1 + 2 + ... + i-1 + i
which is equal to i*(i+1)/2 = (i²+i)/2 by an identity by Gauss. The maximum value for i such that this expression is smaller than n is can be obtained by elementary calculation as follows. If we require
(i²+i)/2 <= n
which means
i²+i-2n <= 0
we can use the formula for reduced quadratic equation to obtain
i <= -1/2 + sqrt(1/4+2n)
which is in O(n^{1/2}). In each iteration of the outer loop, the inner loop takes n-s iterations, which very roughly can be estimated by n (but this is very imprecise, I believe the overall analysis can be made more precise). In total, this yields a bound of O(n^{1/2}*n)=O(n^{3/2}).