What is wrong with this method using an int[][]? - java

This method is supposed to return true if there is more than one 1 in a column of a 2D array, yet it doesn't work. I can't figure out what's wrong with it so I thought I'd get some expert opinions.
Example:
10010
01001
10100
will return true because there are 2 ones in the first column.
Here is the code
public static boolean isVert(int[][] x) { //checks for more than one 1 in columns
int count = 0;
boolean break2 = false;
boolean check = false; //false means no 2 (or more) queens in same column
for (int i = 0; i < x.length; i++) {
count = 0;
for (int j = 0; j < x[i].length; j++) {
if (x[i][j] == 1) {
count++;
}
if (count > 1) {
break2 = true;
check = true;
break;
}
}
if (break2) {
break;
}
}
return check;
}

You break at the first occurance of 1 in whole array, which is probably not the expected result.
Explanation of how your code works:
loop until counter i is less than length of array (number of rows in array)
loop until counter j is less than length of i-th row (number of columns or elements in array)
check if element on i-th row and j-th column is 1, if true, increase variable count by one
if count is greater than 1 (this means it has to be 2 or greater) set break2 and check to true, break
if break2 is true (which is as count is > 2 and first loop breaks), break this loop too:
this happens in 1st row of your example table
end of loops, return check (which is true because 1st row contains 2 ones)
The problem in your code is that you break when you find your first row that satisfies your condition, but you do not (necessarily) check all the rows in given array.
I have corrected the code for you, hopefully it works (untested)
public static boolean isVert(int[][] x) { //checks for more than one 1 in columns
int count = 0;
for (int i = 0; i < x.length; i++) {
int rowCount = 0;
for (int j = 0; j < x[i].length; j++) {
if (x[i][j] == 1) {
rowCount++;
}
if(rowCount > 1) {
count++;
break;
}
}
}
// returns true if count of lines containing 1 equals length of array,
// if not, returns false
return count == x.length;
}

Start of by improving your naming convention. Your code has many variables named by their contents, instead of named by how they are used. For example:
boolean check = false; // false means no two queens in the same column.
instead of
boolean twoQueensInColumn = false;
and the other example
boolean break2 = false;
instead of the more reasonable
boolean continueLooking = true;
Plus, it is a very good idea to avoid using variables as place holders for loop escaping logic. For example, the two stanzas
...
if (count > 1) {
break2 = true;
check = true;
break;
}
}
if (break2) {
break;
}
are a breeding ground for bugs, requiring a lot of debugging to ensure they work "right now" which will break just as soon as you modify the code. Much better would be
boolean keepLooking = false;
for (int row = 0; keepLooking && (row < board.length); row++) {
int queensInColumn = 0;
for (int column = 0; keepLooking && (column < board[row].length, column++) {
if (board[row][column] != 0) {
queensInColumn++;
}
if (queensInColumn > 1) {
keepLooking = false;
}
}
}
The main difference being the control logic is in the loop "conditional" block, where it belongs.

I would recommend turning your integers to string and using the .contains() method and looping through that. This would make the code easier to understand.

Related

Using return vs While(condition) methods To Break Loops

I'm doing a little google interview question. Find the pair of numbers in a loop that add up to the number given. I found the numbers 2 and 6 that make up 8 so I say match = true so that the while loop stops, however it still proceeds until it finds the second which is 6 and 2 however, those numbers I have already found just the other way around and I had expected my loop to break as my if statement states if there is any 2 numbers that give the sum, match = true therefore terminating the loop, I guess I am wrong though.
However, if I get rid of the while statement and just return; once a match is found it breaks without looking for the second match (which I want it to).
Why is this happening, the logic of both seems the exact same to me.
Using the while(condition) Method
public class Main {
public static void main(String[]args){
int[] list = new int[]{1,2,1,1,1,6};
boolean match = false;
int sumNeeded = 8;
while(!match){
for(int i = 0; i < list.length; i ++){
for(int j = (list.length -1); j >= 0; j --){
if(list[i] != list[j]){
if(list[i] + list[j] == sumNeeded){
System.out.println("The numbers are = " + list[i] + " & " + list[j]);
match = true;
}
}
}
}
}
}
}
Using return
public class Main {
public static void main(String[]args){
int[] list = new int[]{1,2,1,1,1,6};
int sumNeeded = 8;
for(int i = 0; i < list.length; i ++){
for(int j = (list.length -1); j >= 0; j --){
if(list[i] != list[j]){
if(list[i] + list[j] == sumNeeded){
System.out.println("The numbers are = " + list[i] + " & " + list[j]);
return;
}
}
}
}
}
}
In your while-loop implementation, if the array doesn't have the desired pair at all it would result in an infinite loop. There is no need for the while statement in your solution.
After you enter into the while loop, you look for all the possible pairs in the array and then check for their sum. If it equals the desired sum, you make the boolean variable match as true.
But, until the nested for loop is completely executed (i.e., all the possible pairs are checked) we do not check for the while condition. The entire nested for loop is executed in one iteration of the while loop. Then, the while loop condition is checked again.
As by the end of the first iteration of the while loop all the possible pairs are accounted for, there is no need for a while loop.
Moreover, there are other logical errors in your implementation. The correct brute-force implementation is as follows:
public class Main {
public static void main(String[]args){
int[] list = new int[]{1,2,1,1,1,6};
boolean match = false;
int sumNeeded = 8;
for(int i = 0; i < list.length; i ++){
for(int j = (list.length -1); j > i; j --){
if(list[i] + list[j] == sumNeeded){
System.out.println("The numbers are = " + list[i] + " & " + list[j]);
return;
}
}
}
}
}
The inner-for loop is modified to reduce the double-counting of the unordered pairs. Whenever a match is found and printed, we exit the function.
You may also add a break statement inside the while loop in your initial implementation.
if(match == true) {
break;
}
The while condition continues to execute the first and second for-loop until it's finished where as with return it stops execution entirely from the first and second loop.
To fix the while loop you could use a label and then break from that.
firstLoop:
for(int i = 0; i < list.length; i ++) {
match = true;
break firstLoop;

How to break out of nested loops

I'm currently making a program where nested loops are needed to search through an array to find a spot for good input within the array. Here is an example:
public void placePiece(int column) {
boolean goodInput = false;
while(!goodInput) {
for(int x = 5; x >= 0; x--) {
if(boardStatus[x][column] == 0) {
setRow(x);
boardStatus[x][column] = 1;
goodInput = true;
break;
}else if(boardStatus[0][column] == 1) {
goodInput = false;
break;
}else{
}
}
}
}
The method takes a parameter which is the column in which the piece should be located (received by a mouse listener). If the column in the 2D array is already filled to the top, the program gets stuck in an endless loop within the "else if", and I'm unsure how I would break out of this loop. How could I break out of this loop if there is bad input so that the user can try to give another column as input.
An easy way is to use a labeled break statement.
myLabelName:
for(outer loop)
for(inner loop)
if(condition)
break myLabelName;
This is useful when you'd rather not waste time iterating over other objects/items when you've found what you needed.
To expand, when you use just break; (without a label) it will exit the parent loop.
Ex:
myLabelName:
for(outer loop){
for(inner loop){
if(condition){
break myLabelName; //breaks outer loop
}
else if(other condition){
break; //breaks parent (inner/nested) loop
}
}
}
When you are in elseif loop your are again assigning the goodInput = false; so the while conditions again becomes true and loops continuous forever.
if you want to take input till correct input is received can use do(){}while() loop
Based on the description you provided, I am not sure of the purpose of the else if statement. As I understand you intention, you are checking all of the rows within a certain column to see if that cell has been set or not?
The combination of the while loop and the for loop seems suspect as well. There doesn't seem to be any need for the while loop in this case.
What is supposed to happen if the entire column is filled? Should this method return a status flag?
Can't this be implemented with a single for loop?
for (int x = 5; x >= 0; --x)
{
if(boardStatus[x][column] == 0) {
setRow(x);
boardStatus[x][column] = 1;
break;
}
}
If you want, you can track a flag variable to indicate if you ever found a cell which was empty.
you can use flag or you can use goto statement
flag description
code
bool flag = true;
for (int i = 0; (i < 10) && (flag==true); i++)
{
for(int j = 0; (j < 10) && (flag==true); j++)
{
if (condition)
flag = false;
}
}
Change the parameter AFTER the loop:
public void placePiece(int column) {
boolean goodInput = false;
while(!goodInput) {
for(int x = 5; x >= 0; x--) {
if(boardStatus[x][column] == 0) {
setRow(x);
boardStatus[x][column] = 1;
goodInput = true;
break;
}else if(boardStatus[0][column] == 1) {
goodInput = false;
break;
}else{
}
}
goodInput = true; // <-----
}
}

Java 2D array encirclement

I am tasked to make a program which returns true if in a 2D array 1-s encircle 0-s.
I tried something like this, but i cant find the right solution.
public boolean checkGameState(){
for(int i=0;i<fields.length;i++){
for(int j=0;j<fields.length;j++){
if(fields[i][j]!=0){
if(row(i,j){
return true;
}
}
}
}
return false;
}
private boolean row(int a, int b){
int checkI=a;
int checkJ=b;
while(fields[checkI][checkJ]==1){
checkJ++;
}
while(fields[checkI][checkJ]==1){
checkI++;
}
while(fields[checkI][checkJ]==1){
checkJ--;
}
while(fields[checkI][checkJ]==1){
checkI--;
}
return a==checkI && b==checkJ;
}
The 2D array looks something like this:
111100
100100
100101
111100
001100
For this array the method should return true.
The easiest way might be to use a flood fill algorithm to eliminate all the zeros that are not encircled by ones, and then checking whether there are any left.
First, put all the zeros directly on the "fringe" of the 2D array into a queue. Then, use the flood fill algorithm to turn all of those into a different number (e.g., 2), and add the nodes next to them to the fringe set (either diagonally or only direct neighbours). Repeat until there are no more nodes in the fringe. Finally, check whether there are any more zeros in the array. If so, those were not connected to the fringe region and thus had to be "encircled" by ones.
// test data set up
int[][] data = {{1,1,1,1,0,0},
{1,0,0,1,0,0},
{1,0,0,1,0,1},
{1,1,1,1,0,0},
{0,0,1,1,0,0}};
int N = data.length, M = data[0].length;
// create queue of zeros on the "fringe"
Queue<int[]> fringe = new LinkedList<>();
for (int i = 0; i < N; i++) {
if (data[i][0 ] == 0) fringe.add(new int[]{i,0 });
if (data[i][M-1] == 0) fringe.add(new int[]{i,M-1});
}
for (int j = 0; j < M; j++) {
if (data[0 ][j] == 0) fringe.add(new int[]{0 ,j});
if (data[N-1][j] == 0) fringe.add(new int[]{N-1,j});
}
// do flood fill until no more zeros reachable
while (! fringe.isEmpty()) {
int[] next = fringe.poll();
int i = next[0], j = next[1];
data[i][j] = 2;
for (int di = -1; di <= 1; di++) {
for (int dj = -1; dj <= 1; dj++) {
try {
if (data[i+di][j+dj] == 0) fringe.add(new int[]{i+di, j+dj});
} catch (ArrayIndexOutOfBoundsException e) {}
}
}
}
// check for remaining zeros
boolean encircled = false;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
System.out.print(data[i][j]);
encircled |= data[i][j] == 0;
}
System.out.println();
}
System.out.println(encircled);
Example output:
111122
100122
100121
111122
221122
true
The complexity should be on the order of O(NxM), since each of the NxM nodes can only appear once in the queue (plus a bit of overhead for constructing the queue and finding remaining zeros).
Please note that I have assumed that you need rectangle shape surrounding
You need to find sequences for 3 or more 1 in one row.
xx1111xx // x means any number
For each sequence check if there is sequence of the same length 2 or more rows lower.
xx1111xx
xxxxxxxx
xx1111xx
For each "pair" of sequences check if they are connected with 1 on the edges.
xx1111xx
xx1xx1xx
xx1111xx

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.

Finding Zeroes in Sudoku

I had a class assignment (it's already past) where I had to write a Sudoku solver. I was able to create a method that can solve for each missing number. But I'm having trouble creating a method to find which cells I need to solve. I'm supposed to take a 2D array and fill in the missing number (represented by 0's).
I've put some of my code below, but not all of it (even though the assignment has passed, I respect the profs wishes).
public class SolveSudoku {
private static int[][] grid = new int[9][9];
public static int[][] getSolution(int[][] grid) {
for (int i = 0; i < 9; i++) {
System.arraycopy(grid[i], 0, SolveSudoku.grid[i], 0, 9);
}
int n = getZero();
return getSolution(n);
}
private static int[][] getSolution(int n) {
if (n == 0) {
return grid;
}
Cell cell = getZero();
int row = cell.row;
int column = cell.column;
for (int number = 1; number <= 9; number++) {
//checks cell using another method
//I have booleans that return true if the number works
}
return null;
}
private static int getZero() {
return 0;
}
private static class Cell {
int cell = 0;
int row = 0;
int column = 0;
int number;
}
}
I have the getZero method which has to find each zero in the grid (0's represent a missing number) so I can solve it. What should I do in getZero to find the cells I need to replace?
You don't check if the number is repeated in the same 3x3 square (only rows and columns).
I don't get what do you mean by "finding zeroes". In fact it is meaningless, solving the sudoku from the first row or the last one has no effect in the solution. I'll explain what did I do for the same trouble.
A cell is not an int, is an object. In the object I store a value (the number if it is found, 0 if not) and a boolean[9]. False means (index + 1) is discarded because it is in the same row/column/square, true means it is not decided yet. Also, 3 Lists (Vectors, Sets, whatever).
A list of 81 cells (you can make it a bidimensional array if you wish).
9 Lists/Vectors/Sets representing rows, 9 representing columns, 9 representing square. Each of the 81 cells is assigned to its row/column/square. Inside each cell you store the references to the list to which it belongs to.
Now comes the execution part. In a first iteration, every time you find a non-zero (a number fixed in the sudoku), you loop through the lists to which the cell belongs. For each cell in those lists, you mark the boolean assigned to that number to false.
You loop through cells, each time you find a 0 you check how many of the booleans in the cell are true. If it is 1 (all other 8 possible values have been discarded), it is the value of the cell. You set it, and as in 4) you get the list to which it belongs and mark that number to false in every cells. Loop until you get a solution, or an iteration in which you cannot set any number (no solution available directly, must start with backtracking or similar).
Remember before getting at the keyboard, to have a clear idea about what the question is and how would you resolve it without a computer. If you do not know what you want to do, the computer won't help (unless you post in stackoverflow)-
From what I can tell you want to find the first 0-valued cell in grid. I'll define first as the first zero containing column in the lowest zero-containing row.
This can be done using a naive search:
private Cell getZeroCell(){
int rz = -1;
int cz = -1;
outer: for(int row = 0; row < grid.length; row++){
for(int col = 0; col < grid[row].length; col++){
if(grid[row][col] == 0){
rz = row;
cz = col;
break outer;
}
}
}
if(rz == -1 || cz == -1){
// no zeros found
return null;
}else{
// first zero found at row `rz` and column `cz`
Cell cell = new Cell();
cell.row = rz;
cell.column = cz;
return cell;
}
}
Get the "number" of the first cell containing a zero (counting left to right, then top to bottom, 0-indexed):
private int getZeroInt(){
int rz = -1;
int cz = -1;
outer: for(int row = 0; row < grid.length; row++){
for(int col = 0; col < grid[row].length; col++){
if(grid[row][col] == 0){
rz = row;
cz = col;
break outer;
}
}
}
if(rz == -1 || cz == -1){
// no zeros found
return -1;
}else{
return rz * grid[0].length + cz;
}
}
Get the number of cells containing a zero:
private int getNumZeros(){
int count = 0;
for(int row = 0; row < grid.length; row++){
for(int col = 0; col < grid[row].length; col++){
if(grid[row][col] == 0){
count++;
}
}
}
return count;
}

Categories