complexity of code - java

what is the complexity of a program having only one loop, is it log n?
can someone give me some ideas about estimating complexity of codes?

Well, that really depends on what is going on in that loop.
This loop is linear time, i.e., O(n):
int sum = 0;
foreach( int i in SomeCollection )
{
sum += i;
}
However, consider a loop which performs a substring search during each iteration. Now you have to consider the complexity of the string searching algorithm. Your question can't be answered as it stands. You will need to provide a code sample if you want a meaningful answer.

Software Complexity
There is a field of study that attempts to quantify exactly that.
It's called cyclomatic complexity.
In this case, I believe your complexity rating would be p = 2, because the loop is conditional and that means there are two paths through the method.
Time complexity
If you are referring to time complexity, it's still just O(1) unless the loop iteration count is derived via a polynomial or exponential function, perhaps indirectly because the method is itself called in a higher loop, or because the loop counter is effectively multiplied by string operations or something at a lower level.

To get the Big-O complexity of a piece of code, you need to ask yourself "how many iterations are done"?
The problem is of course, that it isn't always easy to figure it out from the code itself, sometimes it's just better to look at the big picture and calculate the amount of operations done.
Examples:
For (i = 0 ; i < n ; i++ ) {
//Do stuff
}
This is a complexity
For (i = n ; i > 0 ; i= i/2 ) {
//Do stuff
}
This is a complexity... Because in each iteration i is cut in half.
void Mess (int n) {
for (i = 0 ; i < n ; i++) {
//Do stuff
Mess(n-1);
}
}
Now this looks like a simple loop, nut because it calls itself with recursion, it's actually quite a mess.... Each iteration calls itself n times with n-1.
So here it would be easier to think from the end. If n == 1 , there's 1 iteration. If n == 2 then it calls the previous scenario twice.
So if we'll call the function , we can see what we'll get this recursively:
Which in the end will of course give us n!
Bottom line, it's not always trivial.

If there's just one loop, it's probably the number of times that loop's body executes.... But of course you may have many hidden loops in library calls. It's easy to make a loop that executes n times O(n^2) or worse if you have strlen, memcpy, etc. taking place inside the loop body.
Or even worse, if you have a library (or language) with regular expressions and their regex implementation is naive (like Perl), it's easy to make a program with just a single loop O(2^n)!! This cannot happen with a correctly written regex implementation.

You can easily predict the computation time and complexity of your code with some tools such as "trend-prof"(https://pdfs.semanticscholar.org/8616/7f320e230641299754e0fbd860c44f5895f0.pdf)
For the same purpose on R codes, the GuessCompx library available in Github.

If it is Big-O time complexity you are asking about, then for loop it is n times complexity of whatever is within the loop, where n is loop count limit.
So. if the code inside loop is taking constant time to execute, i.e. if its time complexity is O(1), then the complexity of the loop will be O(1*n) = O(n).
In the similar way, if within the loop you have another loop which will make m steps, then your entire code is O(n*m), and so on.

Related

Runtime analysis for the partitioning of an array with Quicksort

Im working on a research paper about quicksort for school and thus I have to make a precise runtime analysis on best and worst case for my algorithm but im struggling with the part of my while-statements. I understand why its log(n) since you have so many recursive calls that you have n/2^k = 1 and this equation gives you n = 2^k, k = log2(n) and so on ... well since i did understand the recursive calls this part does not really matter but what matters is my following code:
}
}
I have to specify the "cost" for each statement in dependence of my elements n.
So i added a +1 for every if statement since they are simple statements and now i dont now how to get the cost for the while loops. The outer loop runs until the pointers i and j cross so the outer loop gets execuated at least n/2+1 (+1 for the exit condition) - but i cant find out how often the inner two while loops run. I thought that they would run also n/2 times but this cant work since our teacher taught us that we have to multiply the costs whenever we have nested statements which would result in a (n/2+1)*((n/2)+1)+((n/2)+1)) which is clearly n^2 and not O(n) ...
And yes i have to add a +1 for each abort condition and if statement altough they dont really matter ...
I hope you can help me by telling me whats my mistake that i get a O(n^2) runtime although it has to be O(n)
Side note: I think for the while-loops it doesnt matter if its the best or worst case so dont mind that
Thanks in advance
ChampSilver
The reason why the worst case run time is O(n) is that if you have a careful look at the code, you realize that you visit each array index at most once:
observe that index i only increases at size, and index j only decrease, therefore you'll go at most once over each index.
For example, if you have an array a[] of size 10, then the initial index i will be 0, and j will be 9. x will be (randlomly) somewhere in between, let's say x=4.
Then, the outer while loop enters, and the first inner while loop increases index i until a[i] >= a[x].
The second inner while loop does the same to index j, for the opposite direction.
But the sum of total iterations of both inner loops is at most 10. At which point the next outer while loop check will return false and no second iteration will occur.
Lets start with this:
our teacher taught us that we have to multiply the costs whenever we have nested statements which would result in a (n/2+1)*((n/2)+1)+((n/2)+1)) which is clearly n^2 and not O(n)
This is only true if the looping variables in inner and outer loops are independent of each other.
eg.
for i in range(1..10):
for j in range(1..10):
do something
This is because, for every value of i, inner loop iterates for all values of j. So, this is O(n^2). Now, lets look the other example:
for i in range(1..10):
for i in range(1..10):
do something
In this case, the outer loop runs only once as when inner loop exits, condition for outer loop also discontinues. So, this is, O(n).
Now, lets look at your while loops.
The outer condition is while i is less than j. Inside, we are always incrementing i and decreasing j. So, in this case, the total number of times while statements (all 3) are executed will be the upper bound on i + j, which is 2n. So, complexity is O(2n) or, O(n).
EDIT:
I am making this edit to explain what "complexity" means, practically.
It is a way of approximating/calculating, number of iterations that are made in total, all loops and instructions combined, as size of input increases. So, if you really want to know that, just assign a variable, say a and add 1 to a as the 1st line of every loop. Then print a for different input sizes and you will know what O() notation means, theoretically vs practically.

How to work out worst-case run time complexity of this simple algorithm

I am trying to learn how to work out worst case run time complexity and I was wondering if someone could explain in detail how to work it out for the code below by highlighting all the operations etc.... Sorry for the awful code example, I'm very aware it is the most pointless method ever!
public int two(int[] n){
int twosFound=0;
int other=0;
for (int i = 0; i < n.length; i++) {
if (n[i]==2) {
System.out.println("2 is found");
twosFound++;
}
else other++;
}
return twosFound;
}
Start with the basic building blocks, and then work your way upwards:
initializing an int variable does not depend on the array length, therefore it is O(1).
(By the way, it is a terrible idea to call the array n when you want to talk about O(n). This can easily lead to confusion.)
Accessing n.length takes constant time. On the other hand, if n were a linked list or some other data structure, you would have to further analyze it.
Accessing n[i] takes constant time.
System.out.println takes constant time, since it neither depends on the array length nor on the array contents.
Incrementing an int variable takes constant time.
The if statement takes the worst of whatever its components take; in this case it is constant time.
The for loop iterates linearly over the array, therefore it takes O(n.length), multiplied with O(whatever happens inside the body of the for statement).
In this case, this is O(n) * O(1) = O(n).
Your worst case complexity does not differs from the other cases. Its because of your algorithm. Its running time is solely dependent on the number of elements in the array. You test each element to satisfy a condition, the more elements you have the longer it will take the algo to run.
In fact it clear that time complexity is O(number_of_elements). It means that time is linear dependent on the number of elements. If you take twice bigger array the time will also increase twice.
The time complexity if O(n) (actually, exactly n) because control accesses all n elements of the array. (plus there are no extra conditions to terminate the loop)

Finding the computational complexity of a nested loop

I am having a hard time getting the complexity of this for-loop
for (i = 4; i < n; i++)
{
for (j = i - 3, sum = a[i - 4]; j <= i; j++)
{
sum += a[j];
}
System.out.println("sum thru" + i + ": " + sum);
}
I was thinking that the complexity of this nested loop is n^2 since it's a nested loop
but someone told me that this is incorrect and nested loops aren't always a quadratic complexity!
I don't really know how to get the complexity in a good way. I've seen lots of articles about Big-O and complexity but they weren't helpful because they were expecting me to know everything, and they examples weren't the same as any of the examples I have.
I am not asking for the answer, I'm asking for the method. Is there any formula or method that will work for everything in this topic? I want to know how to get the number of assignments but unfortunately I have no clue how to do this.
Can someone explain it to me step by step?
You can see the outer loop iterates (n-4) times, since it is starting with 4 and condition is less than only. The inner loop will iterate maximum of 4 times. Because it starts with i-3 and ends in i. So the complexity is 4*(n-4). Hence the complexity is O(n).
I don't think there is any formula that can solve all problems regarding to time complexity of algorithms. For me, the best way to figure out the big-O is going step by step, from the outer process to the inner process. I believe it is also the standard way for a beginner like you and me. For your question, first, the outer loop is O(n), which is straight forward. Then inside each loop, we have an inner process, which is another loop. That loop goes from i-3 to i, which is O(1). Then inside that process, it is a normal assignment statement, which is O(1) again.
We take all together, the big-O will be O(n) * O(1) * O(1) = O(n)

Calculating run time analysis on a few methods

I am preparing for my exam and having a little trouble on run time analysis. I have 2 methods below that I am confused on the run time analysis for:
public boolean findDuplicates(String [] arr) {
Hashtable<String,String> h = new Hashtable<String,String>();
for (int i = 0; i < arr.length; i++) {
if (h.get(arr[i]) == null)
h.put(arr[i], arr[i]);
else
return true;
}
return false;
}
Assuming that hash function only takes O(1) on any key, would the run time simply be O(n) due to in worst case, running through the entire array? Am I thinking of this along the right lines if each hash function takes constant time to evaluate?
The other problem I have seems much more complicated and I don't know exactly how to approach this. Assume these are arrarlists.
public boolean makeTranslation(List<Integer> lst1, List<Integer> lst2) {
//both lst1 and lst2 are same size and size is positive
int shift = lst1.get(0) - lst2.get(0);
for (int i = 1; i < lst1.size(); i++)
if ( (lst1.get(i) - lst2.get(i)) != shift)
return false;
return true;
}
In this case, the get operations are supposed to be constant since we are simply retrieving a particular index values. But in the for loop, we are both comparing it to shift and also iterating over all elements. How exactly would this translate to run time?
A helpful explanation would be much appreciated since I have the hardest time understanding run time analysis than anything in this course and my final is next week.
The short answer: both methods have time complexity of O(n).
For hash, it is clear that both get and put operations take constant time.
For list, if you use the ArrayList implementation(and it is likely), the get method takes constant time as well. This is because an ArrayList in Java is a List that is backed by an array.
Code for ArrayList.get(index) in the standard Java library:
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
RangeCheck probably did two comparisons, which is constant time. Returning a value from an array is obviously constant time. Thus, the get method for ArrayList takes constant time.
As for your specific concern mentioned in the OP:
But in the for loop, we are both comparing it to shift and also
iterating over all elements. How exactly would this translate to run
time?
lst1.get(i) takes constant time. lst2.get(i) takes constant time. Thus, lst1.get(i) - lst2.get(i) takes constant time. The same holds for (lst1.get(i) - lst2.get(i)) != shift. The idea is the sum of a constant number of constant time operations is still constant time. Since the loop iterates up to n times, the total time is O(Cn), i.e., O(n) where C is a constant.
And...it never hurts to have a brief review of the big O notation just before final :)
In general, the O() expresses the complexity of an algorithm wich generally is the number of operations, assuming the cost of each operation is constant.For example O(1000n) would be the similar to writing O(n), because each operation costs 1000, and there are n operations.
So assuming get and put are constant (depends on library implementation) for every value, the time for both would be O(n).
For more information see:
http://en.wikipedia.org/wiki/Big_O_notation
Big-O notation is not very accurate as you omit constant factors and lower order terms. So, even if you have 2 constant operations n times, it will still be O(n). In reality, it will be (1+1)n=2n, but in ordo-notation we round it down (even if it's 10000n). So, for both these cases the run-time will be O(n).
In practice, I suggest typing out the costs for each loop and each operation in the worst case. Start from the innermost nested level and multiply outwards (with only the highest cost of each level).
For example:
for (int i = 0; i<n; i++) { //n times
//log n operation
for (int i = 0; i<n; i++) { //n times
//constant operation
}
}
Here, we have n*(log(n)+n*1)=O(n*n) as n>log(n)
It's worth echoing, but both of these operations are O(n) (for #2, that's the worst case). The key thing to note is the number of critical operations done each iteration through.
For your first snippet, the Hashtable is a bit of a red herring, since access time isn't going to be your largest operation in the loop. It's also the case that, since that Hashtable was just new'd, you'll always be inserting n elements into it.
For your second snippet, you have a chance to end early. If the next elements' difference isn't shift, then you return false right there and then, which was only one operation. In the worst case, you'll be going through all n and returning.

Calculating time complexity of recursive algorithm.

I have just started solving Topcoder algorithm problems and have written this algorithm for SRM 466 Div 2 LotteryTicket problem in Java.
As I am not good with time complexity so if somebody could explain me how to calculate time complexity for this algorithm step by step.
public static String buy1(int price,int...b){
int sum=0; String stat="IMPOSSIBLE";
for(int i=0;i<b.length;i++)
sum=sum+b[i];
if(sum==price)
return "POSSIBLE";
if(b.length>1){
stat=buy1(price,Arrays.copyOfRange(b,0,b.length-1));
stat=buy1(price,Arrays.copyOfRange(b,1,b.length));
}
return stat;
}
For your case , The recurrence relation is
(let b.length() be bn)
___________buy1(p,bn-1) (as (b,0,b.length-1) equivalent is bn-1 in number )
/
buy1(p,bn) ____/
\
\___________ buy1(p,bn-1) (as (b,1,b.length) equivalent is bn-1 in number )
So our problem for n = two sub-problem of n-1 hence our time function T(n) is as follows
T(n)=2T(n-1)+c (For convenience lets eliminate c as it is very less compared to T(n) for this instance )
T(n)=2[2(T(n-2))]
T(n)=2{2[2(T(n-3))]} ===> 2poweri(T(n-i)) -------- equation(1)
The recurrence ends when it meets base condition . Lets say T(0)=c(be base condition) that means t(n-i)=t(0) for base condition .so i=n
Substituting i value in equation(1) we get 2power(n){t(0)}
So our Time function value will be 2power(n) and our complexity of program is equal to bigoh(2power(n))
You can use the recursion tree method and master method to find the complexity.
Check this out for more ideas on how to approach this problem.
As an additional exercise try computing the complexity of merge sort using this.
Interesting question. Lets calcluate it correctly ;)
So we will check the worst situation when condition (sum == price) will never appear.
First let's check complecity when b.length = 1. Then you should use only only one "=" operation inside the cycle:
for(int i=0;i<b.length;i++)
And 2 inside initialization:
int sum=0; String stat="IMPOSSIBLE";
Next step. Lets calculate this task for N.
First you need to do N "=" operations inside first the cycle, 2 inside initialization and 2 operations inside if.
stat=buy1(price,Arrays.copyOfRange(b,0,b.length-1));
stat=buy1(price,Arrays.copyOfRange(b,1,b.length));
Another operations are made inside recursive step. So we can use recurrent formula for this situation, which equals:
f(n) = 4 + n + 2*f(n-1), f(1) = 3
Solution of this equation is:
f(n) = -6+5 * 2^n-n
So complecity of your algo is exponential. O(2^n)
I am ignoring all another operations, except "=" because they will not change asymptotic complexity.

Categories

Resources