Is the time complexity of the following snippet O(n^2)? - c++

I was wondering if the time complexity of the following code snippet is O(n^2):
class Solution {
public:
int numSquares(int n) {
if(n<=0)
return 0;
vector<int> dp(n+1, INT_MAX);
dp[0]=0;
for(int i=1; i<=n; i++) {
for(int j=1; j*j<=i; j++) {
//+1 because you are adding the current `j`
dp[i]=min(dp[i], dp[i-j*j]+1);
}
}
return dp[n];
}
};
I am not sure because in the inner loop, we are checking for perfect squares less than i, which would be very less in comparison to i (and I think so less, that they can be assumed to be constant). In this case then, the complexity would be just O(n). So, can I say that the complexity is O(n) or is it O(n^2)?
Note: The code snippet is a solution to a question from LeetCode.com which apparently has a collection of interview questions.

The outer loop is O(N).
The inner loop is O(sqrt(i)).
The sum will be:
1 + sqrt(2) + ... + sqrt(N)
It's greater than O(N) but is less than O(N^2).
Without going into a very accurate computation of the above sum, I would say, it's close to O(N*sqrt(N)).
Update
From http://ramanujan.sirinudi.org/Volumes/published/ram09.pdf, the above sum is:
C1 + (2.0/3)*N*SQRT(N) + (1.0/2)*SQRT(N) + ....

Related

Find duplicate in unsorted array with best time Complexity

I know there were similar questions, but not of such specificity
Input: n-elements array with unsorted emelents with values from 1 to (n-1).
one of the values is duplicate (eg. n=5, tab[n] = {3,4,2,4,1}.
Task: find duplicate with best Complexity.
I wrote alghoritm:
int tab[] = { 1,6,7,8,9,4,2,2,3,5 };
int arrSize = sizeof(tab)/sizeof(tab[0]);
for (int i = 0; i < arrSize; i++) {
tab[tab[i] % arrSize] = tab[tab[i] % arrSize] + arrSize;
}
for (int i = 0; i < arrSize; i++) {
if (tab[i] >= arrSize * 2) {
std::cout << i;
break;
}
but i dont think it is with best possible Complexity.
Do You know better method/alghoritm? I can use any c++ library, but i don't have any idea.
Is it possible to get better complexity than O(n) ?
In terms of big-O notation, you cannot beat O(n) (same as your solution here). But you can have better constants and simpler algorithm, by using the property that the sum of elements 1,...,n-1 is well known.
int sum = 0;
for (int x : tab) {
sum += x;
}
duplicate = sum - ((n*(n-1)/2))
The constants here will be significntly better - as each array index is accessed exactly once, which is much more cache friendly and efficient to modern architectures.
(Note, this solution does ignore integer overflow, but it's easy to account for it by using 2x more bits in sum than there are in the array's elements).
Adding the classic answer because it was requested. It is based on the idea that if you xor a number with itself you get 0. So if you xor all numbers from 1 to n - 1 and all numbers in the array you will end up with the duplicate.
int duplicate = arr[0];
for (int i = 1; i < arr.length; i++) {
duplicate = duplicate ^ arr[i] ^ i;
}
Don't focus too much on asymptotic complexity. In practice the fastest algorithm is not necessarily the one with lowest asymtotic complexity. That is because constants are not taken into account: O( huge_constant * N) == O(N) == O( tiny_constant * N).
You cannot inspect N values in less than O(N). Though you do not need a full pass through the array. You can stop once you found the duplicate:
#include <iostream>
#include <vector>
int main() {
std::vector<int> vals{1,2,4,6,5,3,2};
std::vector<bool> present(vals.size());
for (const auto& e : vals) {
if (present[e]) {
std::cout << "duplicate is " << e << "\n";
break;
}
present[e] = true;
}
}
In the "lucky case" the duplicate is at index 2. In the worst case the whole vector has to be scanned. On average it is again O(N) time complexity. Further it uses O(N) additional memory while yours is using no additional memory. Again: Complexity alone cannot tell you which algorithm is faster (especially not for a fixed input size).
No matter how hard you try, you won't beat O(N), because no matter in what order you traverse the elements (and remember already found elements), the best and worst case are always the same: Either the duplicate is in the first two elements you inspect or it's the last, and on average it will be O(N).

Time complexity (How is this O(n))

I am having trouble understanding how this code is O(N). Is the inner while loop O(1). If so, why? When is a while/for loop considered O(N) and when is it O(1)?
int minSubArrayLen(int target, vector& nums)
{
int left=0;
int right=0;
int n=nums.size();
int sum=0;
int ans=INT_MAX;
int flag=0;
while(right<n)
{
sum+=nums[right];
if(sum>=target)
{
while(sum>=target)
{
flag=1;
sum=sum-nums[left];
left++;
}
ans=min(ans,right-left+2);
}
right++;
}
if(flag==0)
{
return 0;
}
return ans;
}
};
Both the inner and outer loop are O(n) on their own.
But consider the whole function and count the number of accesses to nums:
The outer loop does:
sum+=nums[right];
right++;
No element of nums is accessed more than once through right. So that is O(n) accesses and loop iterations.
Now the tricky one, the inner loop:
sum=sum-nums[left];
left++;
No element of nums is accessed more than once through left. So while the inner loop runs many times in their sum it's O(n).
So overall is O(2n) == O(n) accesses to nums and O(n) runtime for the whole function.
Outer while loop is going from 0 till the n so time complexity is O(n).
O(1):
int sum= 0;
for(int x=0 ; x<10 ; x++) sum+=x;
Every time you run this loop, it will run 10 times, so it will take constant time . So time complexity will be O(1).
O(n):
int sum=0;
For(int x=0; x<n; x++) sum+=x;
Time complexity of this loop would be O(n) because the number of iterations is varying with the value of n.
Consider the scenario
The array is filled with the same value x and target (required sum) is also x. So at every iteration of the outer while loop the condition sum >= target is satisfied, which invokes the inner while loop at every iterations. It is easy to see that in this case, both right and left pointers would move together towards the end of the array. Both the pointers therefore move n positions in all, the outer loop just checks for a condition which calls the inner loop. Both the pointes are moved independently.
You can consider any other case, and in every case you would find the same observation. 2 independent pointers controlling the loop, and both are having O(n) operations, so the overall complexity is O(n).
O(n) or O(1) is just a notation for time complexity of an algorithm.
O(n) is linear time, that means, that if we have n elements, it will take n operations to perform the task.
O(1) is constant time, that means, that amount of operations is indifferent to n.
It is also worth mentioning, that your code does not cover one edge case - when target is equal to zero.
Your code has linear complexity, because it scans all the element of the array, so at least n operations will be performed.
Here is a little refactored code:
int minSubArrayLen(int target, const std::vector<int>& nums) {
int left = 0, right = 0, size = nums.size();
int total = 0, answer = INT_MAX;
bool found = false;
while (right < size) {
total += nums[right];
if (total >= target) {
found = true;
while (total >= target) {
total -= nums[left];
++left;
}
answer = std::min(answer, right - left + 2);
}
++right;
}
return found ? answer : -1;
}

Running-time complexity of two nested loops: quadratic or linear?

int Solution::diffPossible(vector<int> &A, int B) {
for (int i = 0; i < A.size(); i++) {
for (int j = i+1; j < A.size(); j++)
if ((A[j]-A[i]) == B)
return 1;
}
return 0;
}
This is the solution to a simple question where we are supposed to write a code with time complexity less than or equal to O(n). I think the time complexity of this code is O(n^2) but still it got accepted. So, I am in doubt please tell me the right answer.
Let's analyze the worst-case scenario, i.e. when the condition of the if-statement in the inner loop, (A[j]-A[i]) == B, is never fulfilled, and therefore the statement return 1 is never executed.
If we denote A.size() as n, the comparison in the inner loop is performed n-1 times for the first iteration of the outer loop, then n-2 times for the second iteration, and so on...
So, the number of the comparisons performed in the inner loop for this worst-case scenario is (by calculating the sum of the resulting arithmetic progression below):
n-1 + n-2 + ... + 1 = (n-1)n/2 = (n^2 - n)/2
^ ^
|_________________|
n-1 terms
Therefore, the running-time complexity is quadratic, i.e., O(n^2), and not O(n).

Complexity and Big - O of an algorithm

So I am preparing for an exam and 25% of that exam is over Big-O and I'm kind of lost at how to get the complexity and Big-O from an algorithm. Below are examples with the answers, I just need an explanation of how to the answers came to be and reasoning as to why some things are done, this is the best explanation I can give because, as mentioned above, I don't know this very well:
int i =n; //this is 1 because it is an assignment (=)
while (i>0){ //this is log10(10)*(1 or 2) because while
i/=10; //2 bc / and = // loops are log base (whatever is being /='d
} //the answer to this one is 1+log10(n)*(1 or 2) or O(logn)
//so i know how to do this one, but im confused when while and for
//loops nested in each other
int i = n; int s = 0;
while (i>0){
for(j=1;j<=i;j++)s++;{
i/=2;
} //the answer to this one is 2n +log2(n) + 2 or O(n)
//also the i/=2 is outside for loop for this and the next one
int i = n; int s=0
while (i>0){
for(j=1;j<=n;++J) s++;
i/=2;
} //answer 1+nlogn or O(nlogn)
int i = n;
for(j=1;j<=n;j++)
while(i>o) i/=2;
//answer is 1+log2(n) or O(log(n))
for(j=1; <=n; ++j){
int i-n;
while(i>0) i/=2;
} //answer O(nlog(n))
Number 4: the for loop counts from 1 to N, so it is at least O(n). The while loop takes O(log n) the first time, but since i doesn't get reset, while loop has only has one iteration each successive time through the for loop. So basically O(n + log n), which simplifies to O(n).
Number 5: same as above, but now i does get reset each time, so you have O(log n) done N times: O(n log n).

Trying to calculate running time of an algorithm

I have the following algorithm:
for(int i = n; i > 0; i--){
for(int j = 1; j < n; j *= 2){
for(int k = 0; k < j; k++){
... // constant number C of operations
}
}
}
I need to calculate the algorithm's running time complexity,
I'm pretty sure the outer loop runs O(n) times, the middle loop runs O(log(n)) times, and the inner loop runs O(log(n)) times as well, but I'm not so sure about it.
The final result of the running time complexity is O(n^2), but I have no idea how.
Hope someone could give me a short explanation about it, thanks!
For each i, the second loop runs j through the powers of 2 until it exceeds n: 1, 2, 4, 8, ... , 2h, where h=int(log2n). So the body of the inner-most loop runs 20 + 21 + ... + 2h = 2h+1-1 times. And 2h+1-1 = 2int(log2n)+1-1 which is O(n).
Now, the outer loop executes n times. This gives complexity of the whole thing O(n*n).