We were given the problem for which I came up with a solution. Could somebody help me identify the time complexity for the given solution? Should it be O(n) or O(n^2)? According to me it should be O(n).
Problem
Write a program to print the sum of the elements of an array following the given
below condition.
If the array has 6 and 7 in succeeding orders, ignore the numbers between 6 and 7 and consider the other numbers for calculation of sum.
Eg1) Array Elements - 10,3,6,1,2,7,9
O/P: 22
[i.e 10+3+9]
Eg2) Array Elements - 7,1,2,3,6
O/P:19
Eg3) Array Elements - 1,6,4,7,9
O/P:10
Solution
outer: for (i = 0; i < elementsCount; ++i) {
if (arr[i] == 6) {
int sumBetweenBounds = arr[i];
for (j = i + 1; j < elementsCount; ++j) {
if (arr[j] == 7) {
i = j;
continue outer;
}
sumBetweenBounds += arr[j];
}
sum += sumBetweenBounds;
continue;
}
sum += arr[i];
}
When talking about time complexity, we should differentiate between best-case, worst-case or average-case scenario (https://en.wikipedia.org/wiki/Best,_worst_and_average_case). When it is not mentioned, worst-case scenario is usually intended.
In the worst-case scenario, your algorithm is O(n^2) because of the inner loop running when the array element is 6. In the worst-case, all array elements could be this value.
In the best-case scenario, it is O(n), but this is usually not interesting.
For average-case analysis, you would need to know the distribution of values in all arrays that your algorithm will be run on.
First, your algorithm wont work for an array of only 6's.
Second, Your algorithm complexity is O(n^2), check the case of an array of only 6's.
If there are only 6's you'll keep getting into the inner loop for every element which will give you the mentioned complexity and also keep summing up 6's that you already summed up before.
For example:
int[] arr = new int[]{6,6,6,6};
will give:
//1st iteration
sum += 6+6+6+6;
//2nd iteration
sum += 6+6+6;
//3rd
sum += 6+6;
//4th
sum += 6;
Which in total gives sum=60 instead of 24.
You make solution more complicated that actually problem, you should have use single for loop and you could have used boolean to check weather you want to add element or not
Related
An algorithm that goes through all possible sequences of indexes inside an array.
Time complexity of a single loop and is linear and two nested loops is quadratic O(n^2). But what if another loop is nested and goes through all indexes separated between these two indexes? Does the time complexity rise to cubic O(n^3)? When N becomes very large it doesn't seem that there are enough iterations to consider the complexity cubic yet it seems to big to be quadratic O(n^2)
Here is the algorithm considering N = array length
for(int i=0; i < N; i++)
{
for(int j=i; j < N; j++)
{
for(int start=i; start <= j; start++)
{
//statement
}
}
}
Here is a simple visual of the iterations when N=7(which goes on until i=7):
And so on..
Should we consider the time complexity here quadratic, cubic or as a different size complexity?
For the basic
for (int i = 0; i < N; i++) {
for (int j = i; j < N; j++) {
// something
}
}
we execute something n * (n+1) / 2 times => O(n^2). As to why: it is the simplified form of
sum (sum 1 from y=x to n) from x=1 to n.
For your new case we have a similar formula:
sum (sum (sum 1 from z=x to y) from y=x to n) from x=1 to n. The result is n * (n + 1) * (n + 2) / 6 => O(n^3) => the time complexity is cubic.
The 1 in both formulas is where you enter the cost of something. This is in particular where you extend the formula further.
Note that all the indices may be off by one, I did not pay particular attention to < vs <=, etc.
Short answer, O(choose(N+k, N)) which is the same as O(choose(N+k, k)).
Here is the long answer for how to get there.
You have the basic question version correct. With k nested loops, your complexity is going to be O(N^k) as N goes to infinity. However as k and N both vary, the behavior is more complex.
Let's consider the opposite extreme. Suppose that N is fixed, and k varies.
If N is 0, your time is constant because the outermost loop fails on the first iteration.. If N = 1 then your time is O(k) because you go through all of the levels of nesting with only one choice and only have one choice every time. If N = 2 then something more interesting happens, you go through the nesting over and over again and it takes time O(k^N). And in general, with fixed N the time is O(k^N) where one factor of k is due to the time taken to traverse the nesting, and O(k^(N-1)) being taken by where your sequence advances. This is an unexpected symmetry!
Now what happens if k and N are both big? What is the time complexity of that? Well here is something to give you intuition.
Can we describe all of the times that we arrive at the innermost loop? Yes!
Consider k+N-1 slots With k of them being "entered one more loop" and N-1 of them being "we advanced the index by 1". I assert the following:
These correspond 1-1 to the sequence of decisions by which we reached the innermost loop. As can be seen by looking at which indexes are bigger than others, and by how much.
The "entered one more loop" entries at the end is work needed to get to the innermost loop for this iteration that did not lead to any other loop iterations.
If 1 < N we actually need one more that that in unique work to get to the end.
Now this looks like a mess, but there is a trick that simplifies it quite unexpectedly.
The trick is this. Suppose that we took one of those patterns and inserted one extra "we advanced the index by 1" somewhere in that final stretch of "entered one more loop" entries at the end. How many ways are there to do that? The answer is that we can insert that last entry in between any two spots in that last stretch, including beginning and end, and there is one more way to do that than there are entries. In other words, the number of ways to do that matches how much unique work there was getting to this iteration!
And what that means is that the total work is proportional to O(choose(N+k, N)) which is also O(choose(N+k, k)).
It is worth knowing that from the normal approximation to the binomial formula, if N = k then this turns out to be O(2^(N+k)/sqrt(N+k)) which indeed grows faster than polynomial. If you need a more general or precise approximation, you can use Stirling's approximation for the factorials in choose(N+k, N) = (N+k)! / ( N! k! ).
This algorithm reverses an array of N integers. I believe this algorithm is O(N) because for each loop iteration, the four lines of code are executed once thus completing the job in 4N time.
public static void reverseTheNumbers(int[] list) {
for (int i = 0; i < list.length / 2; i++) {
int j = list.length - 1 - i;
int temp = list[i];
list[i] = list[j];
list[j] = temp;
}
}
There isn't such a thing as 4N time. The algorithm is linear because as you increase the size of the input the runtime of the algorithm increases proportionally. In other words if you doubled the size of list you would expect the algorithm to take twice as long.
It doesn't matter how many operations you do inside your loop - as long as they are each constant time (relative to the input) the runtime of the loop is determined simply by the number of iterations.
Put another way, these four statements are - all together - an O(1) operation.
int j = list.length - 1 - i;
int temp = list[i];
list[i] = list[j];
list[j] = temp;
There's nothing significant about the fact that this sequence of steps is expressed in four statements in Java syntax - experimenting with javap suggests these four lines compiles into ~20 bytecode commands, and who knows how many processor instructions that bytecode gets converted into. The good news is Big-O notation works the same regardless of the particular syntax - a sequence of operations is O(1) or constant time if its execution time is the same regardless of the input.
Therefore you're doing an O(1) operation N times; aka O(N).
Yes, you are correct. The number of operations is linearly dependent on the size of the array (N), making it an O(N) algorithm.
Yes, the complexity of the algorithm is O(n).
However, the exact "time" (because there are no constant factors in asymptotic complexity, check comment below) is not 4 times the size of the array, we could say it is 1/2*(c1+c2+c3+c3) times the size of the array, where 1/2 corresponds to each loop iteration and each c corresponds to the time needed for each operation inside theloop.
It would be 4 times the size of the array, if the algorithm was iterating the whole array 4 times.
I have seen at lot of places, the complexity for bubble sort is O(n2).
But how can that be so because the inner loop should always runs n-i times.
for (int i = 0; i < toSort.length -1; i++) {
for (int j = 0; j < toSort.length - 1 - i; j++) {
if(toSort[j] > toSort[j+1]){
int swap = toSort[j+1];
toSort[j + 1] = toSort[j];
toSort[j] = swap;
}
}
}
And what is the "average" value of n-i ? n/2
So it runs in O(n*n/2) which is considered as O(n2)
There are different types of time complexity - you are using big O notation so that means all cases of this function will be at least this time complexity.
As it approaches infinity this can be basically n^2 time complexity worst case scenario. Time complexity is not an exact art but more of a ballpark for what sort of speed you can expect for this class of algorithm and hence you are trying to be too exact.
For example the theoretical time complexity might very well be n^2 even though it should in theory be n*n-1 because of whatever unforeseen processing overhead might be performed.
Since outer loop runs n times and for each iteration inner loop runs (n-i) times , the total number of operations can be calculated as
n*(n-i) = O(n2).
It's O(n^2),because length * length.
I have an array of N elements and contain 1 to (N-1) integers-a sequence of integers starting from 1 to the max number N-1-, meaning that there is only one number is repeated, and I want to write an algorithm that return this repeated element, I have found a solution but it only could work if the array is sorted, which is may not be the case.
?
int i=0;
while(i<A[i])
{
i++
}
int rep = A[i];
I do not know why RC removed his comment but his idea was good.
With the knowledge of N you easy can calculate that the sum of [1:N-1]. then sum up all elementes in your array and subtract the above sum and you have your number.
This comes at the cost of O(n) and is not beatable.
However this only works with the preconditions you mentioned.
A more generic approach would be to sort the array and then simply walk through it. This would be O(n log(n)) and still better than your O(n²).
I you know the maximum number you may create a lookup table and init it with all zeros, walk through the array and check for one and mark the entries with one. The complexity is also just O(n) but at the expense of memory.
if the value range is unknown a simiar approach can be used but instead of using a lookup table a hashset canbe used.
Linear search will help you with complexity O(n):
final int n = ...;
final int a[] = createInput(n); // Expect each a[i] < n && a[i] >= 0
final int b[] = new int[n];
for (int i = 0; i < n; i++)
b[i]++;
for (int i = 0; i < n; i++)
if (b[i] >= 2)
return a[i];
throw new IllegalArgumentException("No duplicates found");
A possible solution is to sum all elements in the array and then to compute the sym of the integers up to N-1. After that subtract the two values and voila - you found your number. This is the solution proposed by vlad_tepesch and it is good, but has a drawback - you may overflow the integer type. To avoid this you can use 64 bit integer.
However I want to propose a slight modification - compute the xor sum of the integers up to N-1(that is compute 1^2^3^...(N-1)) and compute the xor sum of your array(i.e. a0^a1^...aN-1). After that xor the two values and the result will be the repeated element.
Have this java code for bubblesort:
public void sort() {
for(int i = 1; i < getElementCount() ; ++i) {
for(int j = getElementCount()-1; j >= i; j--) {
if (cmp(j,j-1) < 0) swap(j, j-1);
}
}
}
the method "cmp" and "swap" are as follows:
public int cmp(int i, int j) {
return get(i).intValue()-get(j).intValue();
}
public void swap(int i, int j) {
Integer tmp = get(i);
set(i, get(j));
set(j, tmp);
}
I have now written an improved version of the Bubblesort where the sorting method "sort()" looks like this:
public void sort() {
boolean done = false;
for(int i = 1; i < getElementCount() && !done; ++i) {
done = true;
for(int j = getElementCount()-1; j >= i; j--) {
if (cmp(j,j-1) < 0) {
swap(j, j-1);
done = false;
}
}
}
}
Can anyone explain how to compute the time complexity of the latter algorithm? I'm thinking it's comparing n elements one time, and therefore it has complexity O(1) in its best case, and O(n^2) in it's worst case scenario, but I don't know if I'm right and would like to know how to think on this issue.
The complexity tells the programmer how long time it takes to process the data.
The O(1) complexity says that no matter how many elements it will only take one operation.
Insert a value in an array would have O(1)
E.g.
array[100] = value;
In your best case you will have to loop throught the entire array and compare each element.
Your complexity code is then O(n) where n is number of elements in the array.
In the worst case you will have to run through the array once for each element, that would give a complexity of O(n*n)
I just looked over what you've done and it is exactly the same as the one you had previously listed. You have set a boolean condition done = false and then you are checking the negation of it which will always evaluate to true - exactly the same logic as before. You can remove done in your code and you will see that it runs exactly the same. Just like before, you will have a best case complexity of O(n) and a worst case complexity of O(n^2). There is no way any sorting algorithm is O(1) as at the very least you at least have to move through the list once which gives O(n).
Worst Case : If the array is sorted in the sorted reverse order (descending) , it will show the worst time complexity of O(N^2).
Best Case : If the array is in sorted order, then the inner loop will go through each element at least once so it is O(N) - > (If you break out of the loop using the information in done, which is not present in the code).
At no point can it be a O(1) (In fact it is mathematically impossible to get a lower function than O(N) as the lower bounds for sorting is Omega(N) for comparison based sorts)
Omega(N) is the lowest possible function, as for comparison you have to see all elements at least once.
The best way is to represent your loops using Sigma notation like the following (General Case):
'c' here refers to the constant time of if, cmp, and swap that execute inside the innermost loop.
For the best case (modified bubble sort), the running time should look like this: