I have written a java program in which I am supposed to know that if the two nested for loops can finish their execution in 4 seconds or not If they finish their execution in 4 seconds then the program should continue else break the loop. I have three list A ,B and C and I am performing some operation and adding it to the list B. Even for the small inputs to the list A and C like 3, 6, 8, 4, My program throws run out of memory error
I am using one outer for loop for calculating time. If two for loops couldn't finish their execution in 4 seconds the loop should be terminate. I am using one count variable to keep track of the for loop execution even if for loop finished their execution before 4 seconds i am terminating the outer for loop.
Here is my code :
while(!(A.isEmpty())){
ArrayList<Long> B = new ArrayList<>();
for(long start = System.currentTimeMillis() ; start < System.currentTimeMillis() + 4 * 1000 ; ){
for(long i : A){
for(long j : C){
if(i!=j){
B.add(Math.abs(i-j));
}
}
count++;
if(count==A.size());
break;
}
}
}
What is wrong with this code ? How should I make it correct ?
Thank you.
I think this design isn't really robust. Instead of calling the time function within that loop, I think you could be looking into using two threads here:
Thread A kicks of thread B, and waits for n seconds
Thread B does the computation
When thread A wakes up, it simply checks if the computation is done
Alternatively, your main thread kicks of A and B; and A just comes back and tells you: time to check the results of B now.
And for your real problem; I guess one contributor is here:
B.add(Math.abs(i-j));
You see B (really bad name for a list of numbers btw!) taks Long objects. So that little call there creates at least one Long object per iteration. And you iterate over A and C. Without any sleeps or delays there. This means that your code is doing nothing else but iterating loops and creating new objects to fill that B list.
Now: how many loop iterations do you think you will see in 4 seconds? Enough to create millions and millions of objects?! And then: a dynamically growing list is nice, but you understand what it means when an ArrayList constantly goes over its capacity and needs to grow?! You understand that this means creation of new arrays, and copying around of all values?!
What I am saying is: look carefully how much work is really going on there; and how much (un)boxing of primitive/reference long/Long you got in your code.
One (maybe easy way) to test these ideas: change your code from using List of Longs into using fixed arrays with long values. That will have a nice side effect - it will force you think upfront about how many array slots you actually want to create. In your solution, you just keep looping and adding new objects (as said; leading to constant re-capacity increase operations for your B list).
Statement while(!(A.isEmpty())) will run an infinite loop causing B to be instantiated infinite times.
As a result causing OutOfMemoryError
You Have an infinite loop, while(!(A.isEmpty)) will always be true because inside of your for loops you are never removing any elements from A. This will cause you to add an infinite amount of elements to B becuase of B.add(Math.abs(i-j));
Related
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.
So basically, I have a programming assignment, and it involves two lines at an airline, one for frequent flyers and one for regular flyers. I have a for loop set up that, each time it runs, it determines whether some amount of frequent flyers gets in, some amount of regular flyers, or no one. For a frequent flyer, it is supposed to take 3 minutes to service a flyer, with one "minute" being a single iteration of the loop. For the regular flyers, it will take 5 minutes to service one person, again, with one iteration of the loop being a single minute. How can I determine when someone in the line has been serviced? As in, how can I pull someone out of the line whenever 3 or 5 iterations of the loop have occured, respectively. I'm utilizing a linked list.
I'm not sure I entirely understand your question, but I think I got the idea.
You could use break; to exit the loop (if that's what you're trying to do), and to test the amount of times the loop has been executed, you can use an int. It will look something like this:
int i = 0;
for(initialization, condition, iteration){
//Your code
if(i == 3 | i == 5){
break; //If you have your own method to "pull someone out of the line",
//then insert it here instead of using break, and also insert i = 0.
}
i++;
}
The problem:
We are given a set of n tasks, each having an integer start time and
end time. What is the maximum amount of tasks running in parallel at
any given time?
The algorithm should run in O(n log n) time.
This is a school assignment so i don't need a direct answer but any code snippets are welcome as long as they are in Java or Scala (assignment supposed to be written in scala.)
Some of the hints say that i should take advantage of Priority queues. I read the documentation, but I'm not really sure on how to use them, so any code snippets are welcome.
The input data could for instance be Array[Pair[Int,Int]] = Array((1000,2000),(1500,2200)) and so on.
I'm really struggling to set the Ordering of the priority queue, so if nothing else i hope someone could help me with that.
PS:
The priority queue is supposed to be initialized with PriorityQueue()(ord).
Edit: i came up with the solution using priority queues but thank you for all the answers. You guys helped me figure out the logic!
Soln without using Priority Queue.
Consider the array of tasks as follows:
[(1,2), (1,5), (2,4), ....] // (a,b) : (start_time, end_time)
Step 1 : Construct an array considering start_time and end_time together.
[1,2,1,5,2,4....]
Step 2 : Maintain another array to know whether the time at index i is start_time or end_time
[S,E,S,E,S,E...] // S:Start_Time, E:End_Time
Step 3 : Sort the first array. And make sure to change the index in another array accordingly.
Step 4 : Maintain two variables, parallel_ryt_now and max_parallel_till_now. And traverse the second array as follows:
for i in 1:len(second_array):
if(second_array[i] == "S"):
parallel_ryt_now ++
else
parallel_ryt_now --
if parallel_ryt_now > max_parallel_till_now:
max_parallel_till_now = parallel_ryt_now
Logic :
While traversing the sorted array, when u encounter a start_time, that means a task has started. Thus increment the the parallel_ryt_now and when u encounter an end_time, means that a task has completed, thus decrement the parallel_ryt_now.
This way, at every moment the parallel_ryt_now var stores the parallel running tasks.
Time Complexity = Sort + Traverse = O(nlogn) + O(n) = O(nlogn)
Space Complexity = O(n) (To store the extra array for info about whether time at index i is start_time or end_time )
I hope it helped.
This is similar to this question runtime analysis of the following recursive method
I am trying to analyze this code segment
To analyze this, I saw that the outer loop was going to execute n/c times. And then for every time the outer loop runs, the inner loop will also execute n/c times. Therefore in total, this segment will run n^2/c^2 or O(n^2) if you drop the constant.
Is there also a visual way you can do this as well, similar to (from http://courses.cs.washington.edu/courses/cse373/15wi/lectures/lecture3.pdf) slide 19 ? I tried doing this but got (c *(n)(n + 1))/2 which I wasn't sure was right.
(c *(n)(n + 1))/2
= c*(n^2 + n)/2
= (c/2)*(n^2 + n)
dropping the constants and keeping the highest power of n gives a final answer of O(n^2)
For this problem, here is how would analyze it now
The most times that the outer loop will run is n⁄c and for everytime an iteration of the outer loop runs, the inner loop will also run at most n⁄c times.
Therefore the worst case Big O runtime of this algorithm is O(n2⁄c2) or O(n2)
It must be really basic but I need help. For example, you store monster information in an array, and do for~loop to make each monster attacks/moves in their turn like this
for( i <- 0 to monsters.length-1) monsters(i).act
Then some monsters die during the loop and you have to delete some elements in the array while the loop is still on going. Then the next item in the array could be not really the the next one you want to process.
is there any fast/smart way to make sure each item in an array will be proceed once and only once within the loop, even if you really had to make change to the array during loop?
Scala's collections generally don't assume that you'll be manipulating them while they're using a method like foreach (or executing a for loop). If you want to do things that way, the easiest class to use is Java's java.util.concurrent.ConcurrentSkipListMap.
// This helps you use Java collections like Scala ones
import collection.JavaConversions._
case class Monster(name: String, hp: Int) {}
val horde = new java.util.concurrent.ConcurrentSkipListMap[Int,Monster]
horde put (0, Monster("wolf",7))
horde put (1, Monster("orc",3))
for (h <- horde) println(h) // Prints out both
Iterator.iterate(Option(horde.firstEntry)) {
case None => None
case Some(e) =>
val m = e.getValue
if (m.name=="wolf") horde.remove(1) // Kill the orc
else if (m.name=="orc") horde.remove(0) // Kill the wolf
Option(horde.higherEntry(e.getKey))
}.takeWhile(_.isDefined).foreach(_=>())
for (h <- horde) println(h) // Prints out just the wolf
Now, granted, this is rather a mess, but it does work, and it gives nice random access to your monsters. You have to maintain the keys in a sensible order, but that's not too hard.
Alternatively, as others have indicated, you could add an isAlive or isDead method, and only act on monsters that are alive. Then, after you've passed through the list once, you .filter(_.isAlive) to throw away all the dead monsters (or .filter(! _.isDead)), and run it again.
I would either use a conditional statement to check the monster's isAlive property in the loop before I called act, or do that check inside the act method itself.
I imagine that your monster[i] is not going to die on his turn, but rather off some other hapless monster?
If you're hooked on arrays, or don't mind the processing time (and for what you're doing, i reckon you don't care), just keep a boolean on each monster of isDead.
If a monster dies due to some ... i dunno, reason, just mark the "isDead" as true.
Then, in your monster "act" method, just check if the monster "isDead" or not.
After each loop, you can just prune the list to keep the alive monsters (move all the ones that are alive to a new list and begin again, prune the list in place, whatever is easier for you).
EDIT: This first graph misinterperets your question. However, my solution should still work for you.
What you're asking for is a thread-safe array - one that can be accessed by multiple "threads" of execution at a time. Seeing as you're new to Java, my guess is that your game is not going to be multithreaded, and so if you delete an item in an array, that's going to happen for sure before your next loop runs.
That said, if you really want to, you can add a "monster.dead" boolean function to your array, and set that to true whenever a monster dies. In your loop, then, you'd say:
for( i <- 0 to monsters.length-1)
if (monsters[i].dead == false)
monsters(i).act
Most likely, though, you won't run into this issue.
Edit: just reread your post, and realized that you'll be deleting monsters as your array is running. Remember that each line you execute happens sequentially, so when you remove monsters[i], it will be gone the next time the for loop is evaluated. If you have an array of monsters with 5 monsters in it and you delete the second one, when the loop executes again,
monsters.length - 1
is going to evaluate to 3 now. You'll never run into a moment where you hit a deleted array element.
If you delete an entry in an array, this element would be null.
Therefore you should check every element of your array, e.g.:
for(int i = 0; i <= array.lenght - 1; i++) {
// check null
if(array[i] != null) {
// do stuff
}
}
Hope this helped, have Fun!
make a copy of the original array, and traverse the copy.
if a monster would remove a monster, it would be removed only from the original
Deleting elements from an array while looping over it is generally a horrible idea. What if you delete an element before you reach it in the loop? Should you not actually delete it until the end of the loop, or should you skip over it?
I recommend something more like this:
var monsters = ... initial list of monsters ...
monsters = for (m <- monsters; if m.alive) yield { m.act; m }
Take advantage of yield and if in conjunction with the for loop, which allows you to build a new list.