In the book 'Data structures and algorithms in java' the following Array search method code is provided:
{
int j;
for(j=0; j< nElems; j++) // for each element,
if( a[j].getLast().equals(searchName)) // found item?
break; // exit loop before end
if(j == nElems) // gone to end?
return null; // yes, can't find it
else
return a[j]; // no, found it
}
I am trying to understand why there needs to be a if(j == nElems) check? Wouldn't the method work the same if it were written as:
{
int j;
for(j=0; j <nElems; j++)
if( a[j].getLast().equals(searchName))
return a[j];
return null;
}
it would :P You could declare the j inside the for to limit its scope as well.
In the first implementation what it do is check if it iterated over all elements and didn't find anything, because j was incremented until it is equal the the condition of stop of the for-loop. I.e., it didn't stop because of break, indicating that it found an element.
I prefer your solution because it's easier to read :)
Yes, both of these ways are give the same result.
Well , j never equals to nElems so this condition (j==nElems) is not wrong BUT it's not Working .
You can make it like this (j==nElems-1) but it's steal waste of code , So your algorithm is better than the first one .
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last year.
Improve this question
LeetCode 485
Given a binary array nums, return the maximum number of consecutive 1's in the array.
Example 1:
Input: nums = [1,1,0,1,1,1]
Output: 3
Explanation: The first two digits or the last three digits are consecutive 1s. The maximum number of consecutive 1s is 3.
---------Solution:-------
public int findMaxConsecutiveOnes(int[] nums) {
int maxConsSize = Integer.MIN_VALUE;
int i = -1, j=-1, k=0;
while(k<nums.length){
while(k<nums.length && nums[k] == 1){
k++;
i++;
}
if(nums[k] == 0){
maxConsSize = Math.max(maxConsSize,i-j);
j = i;
}
}
maxConsSize = Math.max(maxConsSize,i-j);
return maxConsSize;
}
Warning: This is not direct answer (for this "do my homework" question)
You should use (or learn to use) debugger in your IDE (trust me, IDE, e.g. Eclipse will help you a lot in your beginnings).
The easiest (I'm not saying smartest) way, how to know what the program is doing (when you need to know, like in this case) is to add some print statements, e.g. add System.out.println("k=" + k) into your program (in a while loop).
You might want to watch this youtube video.
You have an infinity loop. Try run this:
public class Test {
public static void main(String[] args) {
int maxConsSize = Integer.MIN_VALUE;
int[] nums = {1,1,0,1,1,1};
int i = -1, j=-1, k=0;
System.out.println(nums.length);
while(k<nums.length){
while(k<nums.length && nums[k] == 1){
k++;
i++;
System.out.println("k = " + k);
}
if(nums[k] == 0){
maxConsSize = Math.max(maxConsSize,i-j);
j = i;
}
}
maxConsSize = Math.max(maxConsSize,i-j);
System.out.println(maxConsSize);
}
}
Output:
6
k = 1
k = 2
After reading the first 0 you are in infinite loop. You have made this task very complicated :)
It's probably not the best solution, but it should be faster
public int findMaxConsecutiveOnes(int[] nums) {
int maxCons = 0;
int currentCons = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 0) {
if (currentCons > maxCons) {
maxCons = currentCons;
}
currentCons = 0;
} else {
currentCons++;
}
}
if (currentCons > maxCons) {
maxCons = currentCons;
}
return maxCons;
}
}
There are two basic forms of loops:
for-each, for-i or sometimes called ranged for
Use that for a countable number of iterations.
For example having an array or collection to loop through.
while and do-while (like until-loops in other programming languages)
Use that for something that has a dynamic exit-condition. Bears the risk for infinite-loops!
Your issue: infinite loop
You used the second form of a while for a typical use-case of the first. When iterating over an array, you would be better to use any kind of for loop.
The second bears always the risk of infinite-loops, without having a proper exit-condition, or when the exit-condition is not fulfilled (logical bug). The first is risk-free in that regard.
Recommendation to solve
Would recommend to start with a for-i here:
// called for-i because the first iterator-variable is usually i
for(int i=0; i < nums.length, i++) {
// do something with num[i]
System.out.println(num[i]):
}
because:
it is safer, no risk of infinite-loop
the iterations can be recognized from the first line (better readability)
no counting, etc. inside the loop-body
Even simpler and idiomatic pattern is actually to use a for each:
for(int n : nums) {
// do something with n
System.out.println(n):
}
because:
it is safer, no risk of infinite-loop
the iterations can be recognized from the first line (better readability)
no index required, suitable for arrays or lists
no counting at all
See also:
Java For Loop, For-Each Loop, While, Do-While Loop (ULTIMATE GUIDE), an in-depth tutorial covering all about loops in Java, including concepts, terminology, examples, risks
since there's no accessible counter or i in there to reset to zero.
is there any way to play around with continue or break to achieve that?
class CommandLine {
public int[] sort(int array[]) {
int temp;
for (int i=0; i<array.length-1; i++) {//must have used for-each
if (array[i] > array[i+1]){
temp = array[i];
array[i] = array[i+1];
array[i+1] = temp;
i=-1;
}//if end
}//for end
return array;
}//main end
}//class end
Generally, there is no way of doing this: the iterator that is used to "drive" the for-each loop is hidden, so your code has no access to it.
Of course you could create a collection-like class that keeps references to all iterators that it creates, and lets you do a reset "on the side". However, this qualifies as a hack, and should be avoided.
If you need a way to reset the position of your iteration back to a specific location, use a regular for loop.
No, the for each loop internally does not use any counter. Therefore, just use an usual loop like:
for (int i = 0; i < myCollection.size(); i ++) {
// do something
}
More information: Is there a way to access an iteration-counter in Java's for-each loop?
I was reading about implementing B-Tree from Rober Sedgewik's and found this snippet in the else part of search method from this link: http://algs4.cs.princeton.edu/62btrees/BTree.java.html
// internal node
else {
for (int j = 0; j < x.m; j++) {
if (j+1 == x.m || less(key, children[j+1].key))
return search(children[j].next, key, ht-1);
}
}
I banged my head but couldn't understand why he directly starts comparing key with j+1th element of children and not jth.
Could someone please through some light upon this specific point?
If you look at his declaration of the less() method, you'll notice that it uses compareTo.
Essentially, what he wanted to do was key.compareTo(children[j+1].key)
But why would he use j+1 instead of j? To understand this, look at the first part of his conditional statement; he uses j+1 == x.m, meaning that he wants to test to see if j+1 is the limit. If j+1 = x.m, he doesn't want to continue incrementing j, so he returns. However, if it is not the limit yet, check compare the current key with the next key in the list (because the next key exists). IF the next key in the list is "less" than the current key, search for the current key.
In short:
If j+1 doesn't exist, the first half of the if statement will catch it and it will break out of the for loop. Otherwise, check j+1's key.
Is this going to cause unpredictable behavior?
ArrayList<X> x = new ArrayList<>();
//x.add(new X())...
f:
for(int i = 0; i < x.size() -1;)
{
X y = x.get(i);
for(int j = i + 1; j < x.size();)
{
if(a) {
x.remove(j);
continue;
}
if(b) {
x.remove(i);
continue f;
}
j++;
}
i++;
}
I don't think it will be unpredictable, but your style seems wrong to me, so your approach is suspect.
Using a label is a bad idea, and deciding to use it shows that your approach is flawed.
You may want to look at this discussion about deleting on ArrayList, but basically, LinkedList would be fsster:
http://www.velocityreviews.com/forums/t587893-best-way-to-loop-through-arraylist-and-remove-elements-on-the-way.html
But, removing this way will work.
UPDATE:
Oops, just saw a couple of bugs:
if(a) {
x.remove(j);
continue;
}
OK, in this one, you will go back through the loop for j, but you didn't increment j.
if(b) {
x.remove(i);
continue f;
}
This is the same for i.
So, you need a similar change to fix it:
for(int i = 0; i < x.size() -1; i++)
This way, when you hit continue then it will still go to the next element.
It would be better to create an array which contains indexes to remove.
And fill it with indexes in the main for cycle. Than you can do something like this:
Collections.sort(indexesToRemoveArr);
Collections.reverse(indexesToRemoveArr);
for (int indexToRemove : indexesToRemoveArr) {
arr.remove((int) indexToRemove );
}
In that code I remove indexes from end to start. That's why it won't do any problems.
Yes. Compiler will optimize and call x.size() only once. So your terminatin condition becomes incorrect as soon as you remove element.
let say my code look like below
for(..)
for(..)
for(..){
break; //this will break out from the most inner loop OR all 3 iterated loops?
}
Your example will break out of the innermost loop only. However, using a labeled break statement, you can do this:
outer:
for(..)
for(..)
for(..){
break outer; //this will break out from all three loops
}
This will only break out from the inner loop. You can also define a scope to break out from. More from the language specs:
A break statement with no label
attempts to transfer control to the
innermost enclosing switch, while, do,
or for statement of the immediately
enclosing method or initializer block;
this statement, which is called the
break target, then immediately
completes normally.
Yes, without labels it will break only the most inner loop.
Instead of using labels you can put your loops in a seperated function and return from the function.
class Loop {
public void loopForXx() {
untilXx();
}
private void untilXx() {
for()
for()
for()
if(xx)
return;
}
}
From the most inner loop :)
int i,j,k;
for(i = 0; i < 2; i++)
for(j = 0; j < 2; j++)
for(k = 0; k < 2; k++)
{
printf("%d %d %d\n", i, j, k);
break;
}
Will produce :
0 0 0
0 1 0
1 0 0
1 1 0
You should take a look here: http://java.sun.com/docs/books/tutorial/java/nutsandbolts/branch.html
as often mentioned i don't like to break with a label eather. so while in a for loop most of the time i'm adding a boolean varible to simple exit the loop.. (only if i want to break it of cause;))
boolean exit = false;
for (int i = 0; i < 10 && !exit; i++) {
for (int j = 0; j < 10 && !exit; j++) {
exit = true;
}
}
this is in my opinion more elegant than a break..
Many people here don't like labels and breaking. This technique can be compared to using a 'goto' statement, a flow control statement which allows jumping out of a block of code in a non-standard way, obliviating use of pre- and post conditions. Edsger Dijkstra published a famous article in Communications of the ACM, march 1968, 'Goto statement considered harmful' (it's a short read).
Using the same reasoning presented in the article, returning from inside an iteration as suggested by TimW is also bad practice. If one is strict, to create readable code, with predictable entry- and exit points, one should initialize the variable which will hold the return value (if any) at the beginning of the method and return only at the end of a mehod.
This poses a challenge when using an iteration to perform a lookup. To avoid using break or return one inevitably ends up with a while-loop with a regular stop condition and some boolean variable to indicate that the lookup has succeeded:
boolean targetFound = false;
int i = 0;
while (i < values.size() && ! targetFound ) {
if (values.get(i).equals(targetValue)) {
targetFound = true;
}
}
if (!targetFound) {
// handle lookup failure
}
Ok, this works, but it seems a bit clunky to me. First of all I have to introduce a boolean to detect lookup success. Secondly I have to explicitly check targetFound after the loop to handle lookup failure.
I sometimes use this solution, which I think is more concise and readable:
lookup: {
for(Value value : values) {
if (value.equals(targetValue)) {
break lookup;
}
}
// handle lookup failure here
}
I think breaking (no pun intended) the rule here results in better code.
it will breake from most inner loop,
if you want to break from all, you can hold a variable and change its value when you want to break, then control it at the beginning of each for loop