array index out of bounds not fired - java

public static void insertionSort(int[] data) {
for (int i =0; i < data.length; i++) {
int current = data[i];
int j = i-1;
while (j >=0 && data[j] >= current) {
data[j+1] = data[j];
j--;
}
data[j+1] = current;
}
}
the line while (j >=0 && data[j] >= current) should throw array index of bounds when data[-1] for the first time. I dont understand why it does not. Can some one please help
Thank you
Ashok Pappu

Boolean expressions like these are never fully evaluated if the condition can be met earlier.
So...in your case since j >= 0 is false and false && ??? will always be false the second part does not need to get evaluated. This is why data[-1] will never be called.
You can use the same principle for null checks, e.g.
if (object != null && object.isSomething())

If while clause contains more, than 1 expression, splitted by &&, they are executed one by one. This is done to increase performance.
I.e. at first in your code j >= 0 will checks. If j < 0, it false. So, cycle will be interrupted regardless of the 2nd expression.

Related

Does order of conditions matter with multiple conditions in a while loop?

I was not able to find the answer to this question. I was working on an insertion sort method and it wouldn't properly execute:
public static <T extends Comparable<? super T>> void insertionSort(T[] array) {
int length = array.length;
T temp;
for (int i = 1; i < length; i++) { //start of unsorted
temp = array[i]; //save the element
int j = i-1;
while (temp.compareTo(array[j]) < 0 && j >= 0) { // while temp is less than array[j]
array[j+1] = array[j];
j--;
} //end of while
array[j+1] = temp; //as soon as temp is greater than array[j], set array[j] equal to temp
}
}
This returned an ArrayIndexOutOfBoundsException on the while loop line, but when I switched the conditions in the while loop around to this:
while (j >= 0 && temp.compareTo(array[j]) < 0)
it worked. I didn't think in Java the order of conditions in a while loop mattered to the program? This is very strange to me, as I've never seen or heard of order mattering in a statement with && since I assumed that the two while loop lines were equivalent. I was stuck wondering this for a while and couldn't find an answer.
Can someone explain why this is so?
Conditions are evaluated left to right.
Initially, for case j=-1, your code wasn't evaluating the second condition because the first one was throwing an ArrayIndexOutOfBoundsException exception.
while (temp.compareTo(array[j]) < 0 && j >= 0)
However when you switched the conditions like this:
while (j >= 0 && temp.compareTo(array[j]) < 0)
then for the same case (j=-1), since first condition becomes false, then regardless of the second value, the whole condition will always be false; and so the second condition won't be evaluated and hence no exception in this case.
Lets consider the following example:
boolean b = Condition_1 && Condition_2;
Now if the Condition_1 is always false then whatever the value of Condition_2, b will always be false. So when first condition is false of an 'and' then no need to check the value of second condition that is what exactly happened here.
It's exactly error if you use the condition while (temp.compareTo(array[j]) < 0 && j >= 0)
In Java, it checks condition && first and then checks || after.
In the condition && it checks in the order.
Therefore, in your case while (temp.compareTo(array[j]) < 0 && j >= 0), it check this condition temp.compareTo(array[j]) firstly. If j out of the array index, ==> you get error
When you change the condition to while (j >= 0 && temp.compareTo(array[j]) < 0), it check j>=0 firstly, if j = -1 the program cannot go further.

How to find the number of zero elements between sequential non-zero elements

I want to know how many zeros are between sequential non-zero elements in f array. This is how I do it:
int[] f = new int[]{0,0,3,0,0,1};
int start = 0, end = 0;
for (int i=0; i<f.length; i++)
{
if (f[i] != 0 && start == 0)
start=i;
else if (f[i] != 0 && start != 0)
end=i;
}
int cnt = (end-start-1)>=0 ? (end-start-1) : (start-end-1);
The answer is 2 zeros between 3 and 1.
However, in case of int[] f = new int[]{0,3,2,0,0,1} the answer is 3, which is not correct. It should be 2.
Update:
I want to count the number of zeros between LAST left-hand side non-zero element and FIRST right-hand side non-zero element.
Your logic of detecting when there are changes (from 0 to non-0 and from non-0 to 0 elements) is flawed.
You should look at the i and i-1 elements instead. Consider the following:
The start index should be when element i-1 is non-zero and element i is 0.
The end index should be when element i-1 is 0 and element i is non-0 and a start element was found (start > 0, this is to take into account the fact that the array can start with 0 and there were no start sequence).
The next thing to consider is that there may be multiple cases of 0's enclosed in non-0's in the array so each time we encounter an end element, we need to add this to a current count.
Putting this into code:
private static int countZeros(int[] f) {
int start = 0, end = 0, cnt = 0;
for (int i = 1; i < f.length; i++) {
if (f[i-1] != 0 && f[i] == 0) {
start = i;
} else if (f[i-1] == 0 && f[i] != 0 && start > 0) {
end = i;
cnt += end - start;
}
}
return cnt;
}
Some examples:
System.out.println(countZeros(new int[]{0,0,3,0,0,1})); // prints 2
System.out.println(countZeros(new int[]{3,0,0,1})); // prints 2
System.out.println(countZeros(new int[]{3,0,0,1,0})); // prints 2
System.out.println(countZeros(new int[]{3,0,0,1,0,1})); // prints 3
If you want the last 0s group, count backwards.
private static int countZeros(int[] f) {
for (int i=f.length-1; i>=0; i--){
if(f[i]!=0 && i>0 && f[i-1]==0){
i--;
int count=0;
while(i>=0 && f[i]==0){
i--;
count++;
}
if(i==0)
return null;
else
return count;
}
}
return null;
}
Your loops behaviour will have the following effect:
for (int i=0; i<f.length; i++)
{
if (f[i] != 0 && start == 0) //finds only first non-zero in whole array
start=i;
else if (f[i] != 0 && start != 0) //finds last non-zero in whole array
end=i;
}
But by taking the difference you include all non-zeros and zeros in the range. So you need a way to count only zeros between these to points, which is hard to add to the first loop because end will be changing. The easiest solution is to loop a second time from start to end and count the zeros:
int cnt = 0;
for(int i=start; i<end; i++)
if(f[i]==0)
cnt++;
This may not the most efficient solution, but it is a way to build upon your existing logic.

java code keeps throwing exception

My code always throws an exception java.lang.String.charAt at this line in my code :
while(0 == charToInt(value.charAt(startValueAt))){
in the code segment,
private static ArrayList<Integer> stringToArray(String value){
ArrayList<Integer> holder = new ArrayList<Integer>();
int startValueAt = 0;
if(value.charAt(0)=='-'|| value.charAt(0)=='+')
startValueAt= 1;
else
startValueAt = 0;
while(0 == charToInt(value.charAt(startValueAt))){
startValueAt++;
}
int startOfValue = value.length() - (startValueAt - 1);
//to make sure that arraylist is right size and last element ends up at zero as well as find starting index of j with above step
//we use value of startValueAt
for(int i = startOfValue, j = startValueAt; j <= value.length() - 1; i--, j++){
holder.add(0, charToInt(value.charAt(j)));
}
return holder;
}
Here is the stack trace:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 4
at java.lang.String.charAt(String.java:686)
at BigInt.stringToArray(BigInt.java:145)
at BigInt.<init>(BigInt.java:35)
at BigInt.multiplyBySingleDigit(BigInt.java:853)
at BigInt.multiplyPositives(BigInt.java:878)
at BigInt.multiplyOneNegative(BigInt.java:920)
at BigInt.multiply(BigInt.java:778)
at BigInt_Add_Sub_Mul_Div_Mod_Demo.main(BigInt_Add_Sub_Mul_Div_Mod_Demo.java:164)
while(startValueAt < value.length() && 0 == charToInt(value.charAt(startValueAt))){
startValueAt++;
}
You are ignoring the case where the String is all 0s. Then you will call value.charAt(value.length()) which throws the exception.
Using the string "+321", by the last for loop the variable 'j' is set to startValueAt and is supposedly pointing to the last integer, i.e. '1'. In other words the 4th character in '+321'. But then you increment 'j' (with j++) and try to find it in the array. This will give you an out of bounds exception.
while(0 == charToInt(value.charAt(startValueAt))){
startValueAt++;
if (startValueAt>=value.length()) break; /*add this line */
}
(1) You need to make sure that value contains at least one number that is not 0 (otherwise, your while-loop will continue until it wants to get a char from value that is out of bounds / doesn't exist)
An attempt to fix this problem might be changing your while-loop to this:
while(startValueAt < value.length() && 0 == charToInt(value.charAt(startValueAt))){
startValueAt++;
}
(2) In your for-loop:
for(int i = startOfValue, j = startValueAt; j <= value.length() - 1; i--, j++){
holder.add(0, charToInt(value.charAt(j)));
}
the variable j is incremented until it equals value.length(). The problem is, if your string has 4 characters you can access the last character using string.charAt(3).
The problem should be fixed by simply changing j <= value.length() to j < value.length().
Remember, arrays and lists always start at index 0.

Find if Entered Password is valid or not?

This is an interview question. I think the code below, works a bit and has some errors. The problem is as follows -
In 1-9 keypad one key is not working. If some one enters a password then not working key will not be entered. You have given expected password and entered password. Check that entered password is valid or not
Ex: entered 164, expected 18684 (you need to take care as when u enter 18684 and 164 only both will be taken as 164 input)
The code which does above is below.
public static void main(String[] args){
System.out.println(IsAMatch("164","18684"));
}
static boolean IsAMatch(String actual, String expected)
{
char faultyKey = '\0';
int i = 0, j = 0;
for(; i < expected.length() && j < actual.length(); ++i)
{
if(actual.charAt(j) != expected.charAt(i))
{
if('\0' != faultyKey){
if(faultyKey != expected.charAt(i))
return false;
}
else{
faultyKey = expected.charAt(i);
}
}
else{
++j;
}
}
System.out.println("FaultyKey= "+faultyKey);
return (i == expected.length() - 1 && j == actual.length() - 1)? true : false;
}
It is detecting the faulty key correctly (Ex here it is 8), but giving wrong output (As False) Even though the test case used above should give true.
Any suggestions to fix this? If any better method/ideas are most appreciated.
Change the return statement to:
return (i == expected.length() && j == actual.length())? true : false;
The bug is that i and j are both increased first and then checked if they meet the loop condition. Obviously both i and j fail to meet the condition as the control flow breaks out from the loop. Therefore, i and j are exactly equal to expected and actual length respectively.
Moreover, the expression in your return statement is gratuitous. You could just return true at that point of the program as it is a tautology at that stage. I.e. there is no way that you can be at that point in your code and your expression evaluates to false.
static boolean IsAMatch(String actual, String expected) {
char faultyKey = '\0';
int i = 0, j = 0;
for (; i < expected.length(); ++i) {
if (j >= actual.length() || actual.charAt(j) != expected.charAt(i)) {
if ('\0' != faultyKey) {
if (faultyKey != expected.charAt(i)) {
return false;
}
} else {
faultyKey = expected.charAt(i);
}
} else {
++j;
}
}
System.out.println("FaultyKey= " + faultyKey);
return (i == expected.length() && j == actual.length()) ? true : false;
}
Consider the following condition
System.out.println(IsAMatch("164", "186848"));
Your logic will not work, because before i meets the length j would meet the actual length.
you dont need to have condition j < actual.length in for loop.
Your return statement should be :
return (i == expected.length() && j == actual.length()) ? true : false;
or, simpler :
return (i == expected.length() && j == actual.length());
because i and j reach the length of the strings when the loop ends.
The issue is with these two statements:
i == expected.length() - 1
j == actual.length() - 1
Remove the - 1 by each of them and it should work fine.

Need help understanding parts of this class

I need someone to elaborate on certain parts of this code.
class ContinueWithLabelDemo {
public static void main(String[] args) {
String searchMe = "Look for a substring in me";
String substring = "sub";
boolean foundIt = false;
int max = searchMe.length() -
substring.length();
test:
for (int i = 0; i <= max; i++) {
int n = substring.length();
int j = i;
int k = 0;
while (n-- != 0) {
if (searchMe.charAt(j++) != substring.charAt(k++)) {
continue test;
}
}
foundIt = true;
break test;
}
System.out.println(foundIt ? "Found it" : "Didn't find it");
}
}
more specifically, I don't understand this part:
int n = substring.length();
int j = i;
int k = 0;
while (n-- != 0) {
if (searchMe.charAt(j++) != substring.charAt(k++)) {
continue test;
}
}
Why is it necessary to declare j and k in this code at all? I know that there is a reason in it for the if statement
if (searchMe.charAt(j++) != substring.charAt(k++))
but I don't understand what the code is actually doing at this part.
Also, what does
while (n-- != 0)
mean?
while (n-- != 0)
This is just looping around, reducing n by 1 each time around the loop and ending when n (before) reducing it by 1 is not 0.
int n = substring.length();
int j = i;
int k = 0;
while (n-- != 0) {
if (searchMe.charAt(j++) != substring.charAt(k++)) {
continue test;
}
}
This code is starting with j and k at different positions in the string, and then it is looping through comparing the character in the String at that position. j++ just says "use the current value of j, and then afterwards add 1 to it".
++ and -- are pre or post incrementor and decrementor in java.
Imagine the following code to understand the behaviour:
int a = 42
System.out.println(a++) // prints 42
System.out.println(a) // prints 43
System.out.println(++a) // prints 44
System.out.println(a) // prints 44
In fact, it adds or subtracts 1 before or after the statement is processed.
So in your situations, while (n-- != 0) means, that the condition is checked, wether n is not zero and after that decremented by 1.
To achieve the same, you could also write:
while (n != 0) {
if (searchMe.charAt(j++) != substring.charAt(k++)) {
continue test;
}
n = n - 1 // or n-- or n -= 1
}
Your second condition if (searchMe.charAt(j++) != substring.charAt(k++)) compares the character at the index j in searchMe against the character with the index k from substring and after that increments both indices to avoid two more lines, where these two are incremented.
Well, this is some interesting code. To start off, the label on your break is unnecessary.
Next, to your main questions:
n-- is a postfix decrement operator - the current value of n is evaluated, then it is decremented by 1. When n is evaluated next, it will have the value of n-1.
In the context of the code while(n-- != 0) implies that, when n == 1, this loop will still execute, but the next time we see n, we will be viewing 0 instead.
The statement:
if (searchMe.charAt(j++) != substring.charAt(k++)) {
continue test;
}
...indicates that, if the value in the position of the main search string doesn't match up with the value we're looking for, we need to immediately jump to the label test. This allows you to skip the execution of the following two statements after it, and continue looping and looking for positive matches.
j is constantly set to what i is, but it is not always equal to i. If a partial positive match is found, then j will increment faster than i by virtue of the while loop around that statement.
This can be broken down in to the following:
outer: loop(/* for each character in searchMe to max */) {
loop(/* for each character in substring
* starting with current index in outer loop */) {
if(/* this substring does not match */)
continue /* with next outer loop iteration */;
}
/* if inner loop completed
* the substring did match at this index so break */;
}
Out of all the variables, n is actually the one that's not needed. I don't know why it's there except to try to confound. The while loop could just as easily read while(k < substring.length()).
This kind of loop is necessary because to search for a substring you have to search starting at every character:
Loo
ook
ok
k f
fo
for
or
r a
...
a s
su
sub <- found it
Another way to express the same logic is the following but this creates a new object on each iteration:
int max = searchMe.length() - substring.length();
for(int i = 0; i <= max; i++) {
String toTest = searchMe.substring(i, i + substring.length());
if(toTest.equals(substring)) {
foundIt = true;
break;
}
}
Starting with an n >= 0 (string length can not be negative):
while (n-- != 0) {
...
}
is just a substitute for
for (int t = n ; t > 0; t--) {
.... // use t instead of n, no change in your example
}
it iterates just n times (length of substring).
class ContinueWithLabelDemo {
public static void main(String[] args) {
String searchMe = "Look for a substring in me";
String substring = "sub";
boolean foundIt = false;
int max = searchMe.length() -
substring.length(); //the length of what we're going to search through, we
//subtract the substring.Length because if the 3rd to
//last character of searchMe is not equal to the first
//character of substring then searchMe can not contain substring.
test:
for (int i = 0; i <= max; i++) { //repeat until we pass the 3rd to last character of searchMe
int n = substring.length(); //resets n to the length of the substring
int j = i; //resets j to equal i so we search for the next letter in searchMe
int k = 0; //resets k to equal 0 so we search for the first letter in substring
while (n-- != 0) { //repeat this loop until n = 0, each pass will subtract 1 from
//n. this will loop a maximum of 3 times (the number of characters in substring)
if (searchMe.charAt(j++) != substring.charAt(k++)) {
//the if statement above will add 1 to j and add 1 to k after it checks to make sure the
//characters are not equal to each other. if they are equal then it will take the new
//j and k variables and repeat the while loop.
continue test; //if statement true then loop through the 'test' again.
}
}
foundIt = true;
break test;
}
System.out.println(foundIt ? "Found it" : "Didn't find it");
}
}
Oracle doesn't know how to write simple things in a tutorial for beginners.
This part:
int n = substring.length();
int j = i;
int k = 0;
while (n-- != 0) {
if (searchMe.charAt(j++) != substring.charAt(k++)) {
continue test;
}
}
can be changed to:
int n = substring.length();
for (int k = 0; k < n; k++) {
if (searchMe.charAt(i + k) != substring.charAt(k)) {
continue test;
}
}
So, you don't need j and instead of that tricky while you can use a simple for which is more intuitive, because it iterates through the substring.

Categories