Java 2D array encirclement - java

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

Related

How do I shift the contents of an array a la Super 2048?

More specifically, how do I shift the contents of an array like this:
[2 0 2 8]
Into something like this:
[0 0 4 8]
Edit:
By shifting, I mean like a game of Super 2048. Think of this array as one row in a 4x4 game. When I enter the command to 'shift right', the left number would look for the number equal to it, like element 0 being equal to element 2. The number in element 0 then become 0 and the one in element 2 would then add up to 4. If the number fails to find an equal number, it stops to the left of the different number.
I tried manipulating the array's elements directly like the code below, but I had no success.
for(int col = dimension-2; col >= 0; col--)
{
for(int tgtCol = col+1; tgtCol < dimension; tgtCol++)
{
if(initialState[tgtCol] == initialState[col])
{
initialState[tgtCol] += initialState[col];
initialState[col] = 0;
}
/*if(initialState[tgtCol] == 0 && InitialState[col] != 0)
{
initialState[tgtCol] = initialState[col];
initialState[col] = 0;
}
Code for later implementation
*/
else
{}
}
}
This'll work for you,
int[] targetState = new int[dimension];
int tCol = dimension - 1;
for (int i = dimension - 1; i >= 0; i--) {
if (initialState[i] == 0) {
continue;
} else {
if ((targetState[tCol] == initialState[i])) {
targetState[tCol] += initialState[i];
tCol--;
} else if (targetState[tCol] == 0){
targetState[tCol] = initialState[i];
} else {
targetState[--tCol] = initialState[i];
}
}
}
initialState = targetState;
i think inplace shifting is computationally very expensive aproach.

Does this program use the Sieve of Eratosthenes?

I have an assignment as follows,
: Use the Sieve of Eratosthenes to locate and print out all prime numbers from 1 to 1000.
Follow a procedure similar to this:
Write down, in order, all number to be considered.
Cross out 1, since it is not considered prime.
Go to the next number not crossed out; leave it, but cross out all multiples of that number.
Repeat step 3 until you pas the number which is half of the largest number considered. At that point, all numbers not crossed out are the desired primes.
Your algorithm may vary slightly from the one above but speed is important.
I wrote this program out using the knowledge I have of math and arrays however as I was researching Sieve, I had no clue if this was the method.
public class PrimeSieve
{
public static void main( String[] args)
{
int max=1000;
calcPrimes( max );
}
public static void calcPrimes( int max )
{
// each boolean value indicates whether corresponding index
// position is composite (non-prime)
boolean[] array = new boolean[max +1 ];
// mark composites as true
for (int i = 2; i <= (int) Math.sqrt( max ); i++)
{
for (int j = i*i; j <= max; j += i) array [j ] = true;
{
// print indexes with corresponding false values
for (int k = 2;k <= max; k++)
{
if ( !array[ k ] )
System.out.format( k + "\n" );
}
}
}
}
}
Any help would be nice!
The problem is that you do not complete the process of marking off composites before printing out the results, possibly because your loops are nested in a confused sort of way.
public static void calcPrimes(int max) {
// each boolean value indicates whether corresponding index
// position is composite (non-prime)
boolean[] array = new boolean[max + 1];
// mark composites as true
for (int i = 2; i <= (int) Math.sqrt(max); i++) {
for (int j = i*i; j <= max; j += i) array[j] = true;
}
// print indexes with corresponding false values
for (int k = 2; k <= max; k++) {
if (!array[k]) System.out.println(k);
}
}
In this example, I have moved the code to print the primes outside of the loop that performs the sieve.

Fastest way to remove rows in 2D Array

I have a program where I need to remove a set of rows from a byte[][] array. I want to remove every row that has no zeroes in it. Right now I'm using the following methods:
public byte[][] checkRows(byte[][] grid) {
LinkedList<Integer> temp = new LinkedList<Integer>();
boolean willRemove = false;
for (int y = 0; y < grid.length; y++) {
boolean tempCheck = true;
for (int x = 0; x < grid[0].length; x++) {
if (grid[y][x] == 0) {
tempCheck = false;
break;
}
}
if (tempCheck) {
temp.add(y);
willRemove = true;
}
}
if (willRemove) {
int[] rowArray = convert(temp);
return removeRows(grid, rowArray);
}
return grid;
}
public byte[][] removeRows(byte[][] grid, int[] rows) {
int total = rows.length;
int current = 0;
byte[][] retGrid = new byte[grid.length][grid[0].length];
for (int i = total; i < grid.length; i++) {
if (current < total && i-total+current == rows[current]) {
current++;
}
//retGrid[i] = grid[i-total+current].clone();
System.arraycopy(grid[i-total+current], 0, retGrid[i], 0, xsize);
}
return retGrid;
}
public int[] convert(LinkedList<Integer> intList) {
int[] retArray = new int[intList.size()];
for (int i = 0; i < retArray.length; i++) {
retArray[i] = intList.get(i).intValue();
}
return retArray;
}
This gives me a reasonably fast way of removing rows from a 2D Array and replacing them with zero rows at the top of the array. Is there any faster way to achieve the same result?
If it's unclear what the script does, it's for removing full rows in a game of Tetris.
UPDATE: Using System.arraycopy() instead of clone() provides a 5% performance boost for small arrays.
Using a linked list would give O(1) removals, see this answer, since the list must be iterated over anyway.
At first I thought multidim arrays are compact in the sense that it is one contiguous block of memory, but it seems this is not the case. So you don't loose any caching benefits that might have been in effect.
Pity Java has not value types (currently), I'd use one instead of a byte to encode information. Well this is not strictly necessary...
And from a code review perspective, having a bool willRemove in method checkRows is unnecessary since in these cases, temp will have more than one element. I'd try to eliminate that ArrayList allocation altogether if it's not needed - defer it.
IMHO it's too complicated. Drop the LinkedList as this is a terrible thing anyway. Don't bother with collecting the indexes for removal, instead copy every rows to be preserved to another array. Then use arraycopy to overwrite the original.
You're copying whole rows, but you don't have to. Just rearrange them, so the the preserved rows falls down and move the full ones to the top and clean them. There's no memory allocation needed.
As all copying operation work with one dimension only, there's not much to optimize since the most time-consuming operations are probably determining if there's any zero in a row and (now and then) cleaning some rows.
I wonder what machine does it run on as I guess it must be damn fast on even the slowest phones. Btw. CR would be better suited. Think about better names, e.g., tempCheck -> noZeroFound.
This small method executes the desired functionality of the question for the one dimensional case.
private static final void onClearFilledRows(final byte[] pTetris, final int pRowLength) {
int i = 0, j = 0;
/* Track the last valid position of row data. */
int lLastValidIndex = 0;
/* Iterate through each row. */
for(i = 0; i < pTetris.length; i += pRowLength) {
/* Iterate through each cell in the row. */
boolean lContainsZero = false;
for(j = i; j < (i + pRowLength) & !lContainsZero; j++) {
lContainsZero |= pTetris[j] == 0;
}
/* This row is valid. Copy it to the last valid index. */
if(lContainsZero) {
System.arraycopy(pTetris, i, pTetris, (lLastValidIndex++ * pRowLength), pRowLength);
}
}
/* Empty the remaining rows. */
for(i = lLastValidIndex * pRowLength; i < pTetris.length; i++) {
/* Set the element to zero. */
pTetris[i] = 0;
}
}
This logic can then be reworked for the two dimensional case:
private static final void onClearFilledRows(final byte[][] pTetris) {
int i = 0, j = 0;
/* Track the last valid position of row data. */
int lLastValidIndex = 0;
/* Iterate through each row. */
for(i = 0; i < pTetris.length; i ++) {
/* Iterate through each cell in the row. */
boolean lContainsZero = false;
for(j = 0; j < pTetris[i].length & !lContainsZero; j++) {
lContainsZero |= pTetris[i][j] == 0;
}
/* This row is valid. Copy it to the last valid index. */
if(lContainsZero) {
System.arraycopy(pTetris[i], 0, pTetris[lLastValidIndex++], 0, pTetris[i].length);
}
}
/* Empty the remaining rows. */
for(i = lLastValidIndex; i < pTetris.length; i++) {
for(j = 0; j < pTetris[i].length; j++) {
/* Set the element to zero. */
pTetris[i][j] = 0;
}
}
}

Randomly filling a 2d boolean array with equal amounts of both values

I'm trying to find a way to fill a 2d array of length n with boolean values randomly. The array must have an equal amount of each value if n is even, and if n is odd the extra value must be the same boolean each and every time (doesn't matter which one). Any tips on how to do this in Java? I'm currently shuffling arrays that I make with equal amounts of both values, but this isn't truly random because there will always be n/2 (or n/2+1 and n/2-1 for the odd ns) of each value.
Any advice?
Given your requirements, filling the array with the amount you need, then shuffling it, is a good solution.
Make sure to use a truly random shuffling algorithm, such as the Fisher-Yates shuffle, not the "swap a random pair a bunch of times" method. If you're using Collections.shuffle or similar, you don't need to worry about this.
Adapting the Fisher-Yates shuffle to a 2D array is probably the simplest approach.
boolean[][] array = new boolean[rows][cols];
boolean alternating = false;
Random random = new Random();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
int k = random.nextInt(i * cols + j + 1);
int swapRow = k / cols;
int swapCol = k % cols;
boolean tmp = array[swapRow][swapCol];
array[swapRow][swapCol] = alternating;
array[i][j] = tmp;
alternating = !alternating;
}
}
This is pretty much a verbatim implementation of http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_.22inside-out.22_algorithm , except that we're filling the array as we go with falses and trues.
A different approach might be to randomise the position you are placing the next value rather than the value itself. You know ahead of time exactly how many of each value you are placing.
Something like:
List<Integer> indicesList = IntStream.range(0, n * n).collect(Collectors.toList());
Collections.shuffle(indicesList);
indicesList.stream().forEach(n -> array[n % size][n / size] = (n % 2 == 0));
By my understanding that should give you completely random placement of your values and an equal number of each.
Here's a real simple solution a coworker came up with. It looks to me like it would work and be truly random (please let me know if not, I have terrible intuition about that kind of thing), although it's definitely ugly. Would be pretty efficient compared to a shuffle I imagine.
public boolean[][] generateRandom2dBooleanArray(int length) {
int numFalses = (length*length)/2;
int numTrues = (length*length)/2;
if ((length*length)%2!=0) numTrues++;
boolean[][] array = new boolean[length][length];
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++) {
if (Math.random() > 0.5) {//Or is it >= 0.5?
if (numTrues >= 0) {
array[i][j] = true;
numTrues--;
} else {
//Since boolean arrays are false by default, you could probably just break here to get the right anser, but...
array[i][j] = false;
numFalses--;
}
} else {
if (numFalses >= 0) {
array[i][j] = false;
numFalses--;
} else {
array[i][j] = true;
numTrues--;
}
}
}
}
}
return array;
}

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

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.

Categories