This question already has answers here:
time complexity or hidden cost of <Array Name>.length in java
(5 answers)
Closed 9 years ago.
Let's say I have an array:
int[] array = new int[10];
What is the runtime of:
int len = array.length;
I would think that this would be a constant time operations, but today in an interview, the interviewer told me that this would be O(n) because the number of elements would need to be counted.
Additionally, if I have a loop like this:
for (int i = array.length - 1; i >=0; i--) {
something with array[i];
}
Does this entail an extra n operations to get to the end of the array to start the loop? The interviewer came from a C background, so maybe they were mistaken about how Java works, but I didn't want to push it during the interview.
array.length is O(1) and the loop is O(n) overall (assuming the "something" is constant-time).
Is it different for c?
C is different in that, depending on how the array is allocated, you can either find out its size in O(1) time or not at all. By "not at all" I mean that you have to keep track of the size yourself.
(On a personal note, if that's the caliber of interviewers, I would have reservations about coming to work there.)
It is a constant time operation in all of JAVA implementations because JVM has to store this field to check index (it has to throw IndexOutOfBoundsException if index is invalid ).
It might be a good idea to cache array length in local variable because JVM stack access is faster but this improvement is very minor, normally loop body execution will overweight this optimization.
Here's another SO thread that explains the implementation of array.length:
How is length implemented in Java Arrays?
Calling the length property is an O(1) operation, because it doesn't actually count the array, that field is set when the array is created.
Your loop, on the other hand, is an O(n) operation.
Related
I found this solution
https://www.geeksforgeeks.org/count-distinct-elements-in-an-array/
The problem is that time complexity must be at O(n), space complexity must be at O(1), but i can't import any additional libraries and the code must be maximally short. I wasn't able to find a solution with sorting faster than O(nlog n), so i guess i need to find a clever way. And the answer is the third solution from the link above, but it requires additional library. Is it even possible to find a better way?
Edit:
In fact, i need to create a function that works exactly like
java.util.Arrays.stream(myarray).distinct().count();
It must have time complexity at O(n) and space complexity at O(1).
Basically i have to create it using only loops, arrays and if statements. Also it is forbidden to import anything other than import java.util.Scanner; and because of that i can't do it with any ready to use methods like java.util.Arrays.*;.
For example:
Input:
{1,12,3,0,1,3,15,6}
Output:
6
Maximally short solution with O(n) time complexity, using only Java 8+ built-in APIs, i.e. no additional libraries needed.
The code assumes myarray is an array of int, long, double, or object1.
long count = java.util.Arrays.stream(myarray).distinct().count();
1) Object must have valid equals() and hashCode() implementation.
A solution in O(n) time complexity and O(1) space complexity is possible in theory, but it might not be very practical. The basic idea is this:
let aMin be the minimum value of an entry in arr
let aMax be the maximum value of an entry in arr
let seenOnce and seenTwice be boolean arrays
whose indices are in the range [aMin..aMax]
initialize all elements of seenOnce and seenTwice to FALSE
countUnique = 0;
for a in arr {
if (!seenOnce[a - aMin]) {
// seeing `a` for the first time, so count it
seenOnce[a - aMin] = TRUE
countUnique = countUnique + 1
} else if (!seenTwice[a - aMin]) {
// seeing `a` for a second time, so un-count it
countUnique = countUnique - 1
seenTwice[a - aMin] = TRUE
}
}
If the values in arr could be any ints at all, then each of the boolean arrays will contain 2^32 entries, for a total of over 8 billion booleans. That's 1Gb of memory, provided we're careful to implement all those booleans in one bit each. But it is O(1): same 1Gb consumed regardless of whether arr contains two elements or a billion...
I have an integer 667778 and I need to output it as 607008.
I used an array 6,6,7,7,7,8 and xor next similar elements.
I need to this in constant time.
suppose
int arr[]={6,6,7,7,7,8}
int ele=arr[0];
for (int i=1;i<arr.length;i++)
{
if(arr[i]==ele)
arr[i]=0;
else
ele=arr[i];
}
output array arr has [6,0,7,0,0,8]
It is taking O(n) n is size of the array
How can i do this in constant time?
Unless the number given will always be 6 digits (in which case you can hard code it, which is technically constant time, but will give equal performance to the loop), then you can't get constant time because the basis of the problem requires looping through the array in the first place.
Is there are reason you want it to work in constant time anyways, as O(n) is the fastest a program can read the data anyways.
Edit:
After reading your comments, I think you need to come up with a different approach so calculating the XORs won't be inside the loop. I can't provide much more help without the original problem.
I am working through a practice exam for my Computer Science class. However, I am not sure about the question below.
Consider four different approaches to re-sizing an array-based list data-structure.
In each case, when we want to add() an item to the end of the array, but it is full, we
create a new array and then copy elements from the old one into the new one. For each of
the following choices about how big to make the new array, give the resulting complexity
of adding to the end of the list, in big-O terms:
(i) increase array size by 1 item.
(ii) Increase array size by 100 items.
(iii) Double the array size.
(iv) Triple the array size.
Since you call the same System.arraycopy() method reach time regardless, wouldn't the complexity be the same for each?
Since you call the same System.arraycopy() method reach time regardless, wouldn't the complexity be the same for each?
Yes, and no.
Yes - when you actually do the copy, the cost of the copy will be similar in all cases.
(They are not exactly the same if you include the cost of allocating and initializing the array. It takes more space and time to allocate and initialize an array of 2 * N elements than for N + 1 elements. But you will only be copying N elements into the array.)
No - the different strategies result in the array copies happening a different number of times. If you do a complete complexity analysis for a sequence of operations, you will find that options 3 and 4 have a different complexity to 1 and 2.
(And it is worth noting that 2 will be faster than 1, even though they have the same complexity.)
The typical analysis for this involves working out the total costs for something like this:
List<Object> list = new ArrayList<>();
for (int i = 0; i < N; i++) {
list.add(new Object());
}
(Hint: the analysis may be given as an example in your recommended "data structures and algorithms" textbook, or your lecture notes. If so, that is what you should be revising (before doing practice exams!) If not, Google for "complexity amortized arraylist" and you will find examples.)
In Java, for primitive arrays, is reusing arrays signifcantly faster than repeatedly recreating them?
The following snippet is a comparison of the two cases: (a) reuse an array by System.arrayCopy vs (b) repeatedly create an array of specified values, in an intensive loop.
public static void testArrayAllocationVsCopyPerformance() {
long time = System.currentTimeMillis();
final int length = 3000;
boolean[] array = new boolean[length];
boolean[] backup = new boolean[length];
//for (int j = 0; j < length; j++) {
// backup [j] = true;
//}
for (int i = 0; i < 10000000; i++) {
//(a). array copy
//System.arraycopy(backup, 0, array, 0, length);
//(b). reconstruct arrays
array = new boolean[length];
//for (int j = 0; j < length; j++) {
// array[j] = true;
//}
}
long millis = System.currentTimeMillis() - time;
System.out.println("Time taken: " + millis + " milliseconds.");
System.exit(0);
}
On my PC, (b) takes around 2600 milliseconds in average, while (a) takes around 450 milliseconds in average. For recreating an array with different values, the performance gap grows wider: (b) takes around 3750 milliseconds in average, while (a) remains constant, still 450 milliseconds in average.
In the snippet above, if 'boolean' are changed to 'int', the results are similar: reusing the int array takes around one thirds of recreating arrays. In addition, the (b) is also not far less readable than (a); (b) is just slightly less readable than (a) which does not need the 'backup' array.
However, answers of similar questions on stackoverflow or stackexchange regarding Java object creation are always things like "don't optimize it until it becomes a bottleneck", "JIT or JVM handles today can handle these better and faster than yourself", "keep it simple for readibility", etc. And these kinds of answers are typically well received by viewers.
The question is: can the performance comparison snippet above show that array copy is significantly faster compared to array re-creation wrt using short lived primitive arrays? Is the snippet above flawed? Or people still shouldn't optimize it until it becomes a bottleneck, etc?
Can the performance comparison snippet above show that array copy is significantly faster compared to array re-creation wrt using short
lived primitive arrays?
Yes, however you don't really need to prove it. Array occupies a continuous space in the memory. System.arraycopy is a native function, which is dedicated to copying arrays. It is obvious that it will be faster than creating the array, iterating over it, increasing the counter on every iteration, checking the boolean expression whether the loop should terminate, assigning the primitive to the certain position in the array, etc.
You should also remember that compilers nowadays are quite smart and they might replace your code with a more efficient version. In such case, you would not observe any difference in the test you wrote. Also, keep in mind that Java uses just-in-time compiler, which might optimize your code after you run it a lot of times and it decides that the optimization is worth doing.
Is the snippet above flawed?
Yes, it is flawed. What you are doing here is microbenchmarking. However, you haven't done any warm-up phase. I suggest to do some more reading about this topic.
Or people still shouldn't optimize it until it becomes a bottleneck,
etc?
You should never do premature optimizations. If there are performance issues, run the code with profiler enabled, identify bottleneck and fix the problem.
However, you should also use some common sense. If you have a List and are adding elements at the front, use LinkedList, not ArrayList. If you need to copy entire array, use System.arraycopy instead of looping over it and doing it manually.
This question already has answers here:
Using collection size in for loop comparison
(4 answers)
for loop optimization
(15 answers)
Closed 9 years ago.
I would like to ask more experienced developers about one simple, but for me not obvious, thing. Assume you have got such a code (Java):
for(int i=0; i<vector.size(); i++){
//make some stuff here
}
I came across such statements very often, so maybe there is nothing wrong in it. But for me, it seems unnecessary to invoke a size method in each iteration. I would use such approach:
int vectorSize = vector.size();
for(int i=0; i<vectorSize; i++){
//make some stuff here
}
The same thing here:
for(int i=0; i<myTreeNode.getChildren().size(); i++){
//make some stuff here
}
I am definitely not an expert in programming yet, so my question is: Am I seeking a gap where the hedge is whole or it is important to take care of such details in professional code?
A method invocation requires that the JVM does indeed do additional stuff. So what you're doing, at first view seems like an optimization.
However, some JVM implementations are smart enough to inline method calls, and for those, the difference will be nonexistent.
The Android programming guidelines for example always recommend doing what you've pointed out, but again, the JVM implementation manual (if you can get your hands on one) will tell you if it optimizes code for you or not.
Usually size() is a small constant-time operation and so the cost of calling size is trivial compared to the cost of executing the loop body, and the just in time compiler may be taking care of this optimization for you; therefore, there may not be much benefit to this optimization.
That said, this optimization does not adversely affect code readability, so it isn't something to be avoided; often code optimizations that only affect speed by a small factor (as opposed to e.g. an optimization that changes a O(n) operation to a O(1) operation) should be avoided for this reason, for example you can unroll a loop:
int i;
int vectorSizeDivisibleBy4 = vectorSize - vectorSize % 4; // returns lowest multiple of four in vectorSize
for(i = 0; i < vectorSizeDivisibleBy4; i += 4) {
// loop body executed on [i]
// second copy of loop body executed on [i+1]
// third copy of loop body executed on [i+2]
// fourth copy of loop body executed on [i+3]
}
for(; i < vectorSize; i++) { // in case vectorSize wasn't a factor of four
// loop body
}
By unrolling the loop four times you reduce the number of times that i < vectorSize is evaluated by a factor of four, at the cost of making your code an unreadable mess (it might also muck up the instruction cache, resulting in a negative performance impact). Don't do this. But, like I said, int vectorSize = vector.size() doesn't fall into this category, so have at it.
At the 1st sight the alternative you are suggesting seams an optimization, but in terms of speed it is identical to the common approach, because of:
the complexity time of the call of size() function in a java vector has a complexity of order O(1) since each vector has always stored a variable containing its size, so you don't need to calculate its size in each iteration, you just access it.
note:
you can see that the size() function in: http://www.docjar.com/html/api/java/util/Vector.java.html is just returning a protected variable elementCount.