Related
I need to take a 2D array and move everything as far left as possible. It is a 4x4 array and I have tried to do it but either only move certain items or the index goes out of bounds.
The gameBoard array looks like this:
{0 2 4 2}
{0 0 2 0}
{2 2 0 0}
{0 4 0 2}
and after you call the swipeLeft() method it should look like this:
{2 4 2 0}
{2 0 0 0}
{2 2 0 0}
{4 2 0 0}
There is also the issue of placing a zero into the previous index that you moved it from.
I created a double for loop to just loop through the array and tried to code something that would move it over but it hasn't worked.
Here was the code I had so far
public void swipeLeft() {
for ( int r = 0; r < gameBoard.length; r++ ) {
for ( int c = 0; c < gameBoard[r].length; c++ ) {
gameBoard[r][c] = gameBoard[r][ (c+1) %
gameBoard.length];
}
}
}
Based on your desired OUTPUT, it looks like swipeLeft() is supposed to push all non-zero values to the very left of their row, displacing the zeroes to the right of all non-zero values.
If that's correct, this is similar to Old Dog Programmer's approach, except all shifting is done "in place" without creating any new arrays:
import java.util.*;
class Main {
private static int[][] gameBoard;
public static void main(String[] args) {
gameBoard = new int[][] {
{0, 2, 4, 2},
{0, 0, 2, 0},
{2, 2, 0, 0},
{0, 4, 0, 2}
};
System.out.println("Before:");
displayBoard();
swipeLeft();
System.out.println("\nAfter:");
displayBoard();
}
public static void displayBoard() {
for(int[] row : gameBoard) {
System.out.println(Arrays.toString(row));
}
}
public static void swipeLeft() {
for(int[] row : gameBoard) {
// find the first blank (zero) spot
int nextIndex = 0;
while(nextIndex < row.length && row[nextIndex] != 0) {
nextIndex++;
}
// start with the first blank, and shift any non-zero
// values afterwards to the left
for(int col=nextIndex; col < row.length; col++) {
if (row[col] != 0) {
row[nextIndex] = row[col];
row[col] = 0;
nextIndex++;
}
}
}
}
}
Output:
Before:
[0, 2, 4, 2]
[0, 0, 2, 0]
[2, 2, 0, 0]
[0, 4, 0, 2]
After:
[2, 4, 2, 0]
[2, 0, 0, 0]
[2, 2, 0, 0]
[4, 2, 0, 0]
From the example in the question, it appears to me that what is wanted is to shift all non-zero elements to the left, and zero elements are shifted to the right. The order of the non-zero elements is to be retained.
Note that each row is independent of other rows.
One way to approach this is to create a method that works on a 1D array. This method takes a 1D array as a parameter, and returns another 1D array with the elements shifted:
public static int [] zeroShift (int [] arr) {
int [] left = new int [arr.length];
int count = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] != 0) {
left [count++] = arr [i];
}
}
return left;
}
This copies each non-zero element to a new array of the same size, keeping track (count) of how many have been copied so far. Note this relies on left being initialized to all-zeros.
Once that method is working, it can be used for gameBoard on a row-by-row basis:
public void swipeLeft() {
for (int r = 0; r < gameBoard.length; r++) {
gameBoard [r] = zeroShift (gameBoard [r]);
}
// output for testing
for (int i = 0; i < gameBoard.length; ++i) {
System.out.println(Arrays.toString(gameBoard[i]));
}
}
To rotate the array in place, you should roteate the array 3 times:
123456 -> 654312
654321
3456..
....12
public static void shiftLeft(int[] arr, int offs) {
if (offs <= 0)
return;
offs = arr.length - offs % arr.length - 1;
for (int i = 0, j = arr.length - 1; i < j; i++, j--)
swap(arr, i, j);
for (int i = 0, j = offs; i < j; i++, j--)
swap(arr, i, j);
for (int i = offs + 1, j = arr.length - 1; i < j; i++, j--)
swap(arr, i, j);
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
So your code intends to rotate the board one column to the left. Rotate? Well, the numbers you push out on the left might come back on the end, right?
Probably the line
gameBoard[r][c] = gameBoard[r][ (c+1) % gameBoard.length];
should be
gameBoard[r][c] = gameBoard[r][ (c+1) % gameBoard[r].length];
But try to do this stuff with pen & paper, and you should notice that you are going to loose one column/copy the values from the second column into the first, then copy that into the last column again.
You will need to change two items:
store the value from the first column somewhere if you still need it so you can push it into the last one.
only rotate the column data if it needs to be rotated. Or in other words, rotate the remainder of the row if you find a zero. In this case you do not need to remember the first column, as you will overwrite a zero and push a zero into the last column. And then it would not be called rotate but shift.
Exercise this with pen & paper until you can write down instructions for someone else to perform the same operation. Then you are ready to also write it in Java.
For example you have the 2d array Board as shown below:
{0, 2, 4, 2}
{0, 0, 2, 2}
{2, 2, 0, 0}
{0, 5, 0, 2}
You want it to become:
{0, 2, 4, 2}
{0, 0, 4, 0}
{4, 0, 0, 0}
{0, 5, 0, 2}
When there are 2 elements next to each other you need to merge them to make 4 into the left-most place out of those two elements and then make the 2nd element to be 0.
You want to do this with java.
forgot to show my existing loop, this is it below:
for (int row = 0; row < Board.length; row++){
for (int col = 0; col <= Board.length; col++){
if ((Board[row][col] == Board[row][col +1])){
Board[row][col] = 2 * Board[row][col];
Board[row][col + 1] = 0;
}
}
}
Well, I guess that should work. In the loop, you must be careful not to refer to the wrong ( or non-existing) array element.
public static void main(String[] args) {
int[][] arr = new int[][]{{0, 2, 4, 2}, {0, 0, 2, 2}, {2, 2, 0, 0}, {0, 5, 0, 2}, {2, 2, 2, 2}, {2, 2, 2, 0}};
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length - 1; j++) {
if (arr[i][j] == arr[i][j + 1]) {
arr[i][j] = arr[i][j] + arr[i][j + 1];
arr[i][j + 1] = 0;
}
}
}
System.out.println(Arrays.deepToString(arr));
}
Here is one way, focusing only array values that equal 2.
iterate the 2D array.
then iterate over each linear array, checking adjacent values and making the changes.
for(int[] arr : v) {
for(int i = 0; i < arr.length-1; i++) {
if (arr[i] == 2 && arr[i+1] == 2) {
arr[i]+= arr[i+1];
arr[i+1] = 0;
}
}
}
for(int arr[]: v) {
System.out.println(Arrays.toString(arr));
}
prints
[0, 2, 4, 2]
[0, 0, 4, 0]
[4, 0, 0, 0]
[0, 5, 0, 2]
Well I assume that Board variable holds array (quick tip, common convention is to name variable in camelCase (first letter lowercase, then each letter of next work upper, if that variable is constant, then convention is SNAKE_UPPER_CASE)
Your first for is pretty okay, the second one too but it assumes that matrix will be always NxN and will fail if thats not the case or it will not work properly (depending if amount of cols is lower or greater than length of array)
Inside it you dont want to check if the values are equal, you want to check if these values are both equal to 2. And you should check if thats not processing of last column of the row, in that case youll get IndexOutOfBoundException because you want to get value of matrix that is not present.
So with small changes, you will achieve what you want. This code will hopefuly shows my thoughts better
public class MergingTwos {
public static void main(String args[]) {
// Init a matrix
int[][] array = new int[][] { { 0, 2, 4, 2 }, { 0, 0, 2, 2 }, { 2, 2, 0, 0 }, { 2, 2, 0, 0 }, { 0, 5, 0, 2 }};
// Iterating over each row of matrix, in veriable i, the current X index is stored
for(int i = 0; i < array.length; i++) {
// Iterating over each column of row, in variable n, the current Y index is stored
for(int n = 0; n < array[i].length; n++) {
// To prevent index out of bound exception, last element of row wont be processed so as we dont want to proceed if given and next value on row are not 2
if(n == array[i].length -1 || array[i][n] != 2 || array[i][n+1] != 2) {
continue;
}
// To value at given coordinates [i,n] you add values of value on coordinates [i, n+1]
array[i][n] = array[i][n] + array[i][n+1];
// And setting next element to 0
array[i][n+1] = 0;
}
}
// Printing the result
for (int[] x : array) {
for (int y : x) {
System.out.print(y + " ");
}
System.out.println();
}
}
}
I'm studying the Conway's Game of Life to implement it on my own, and came across the following implementation with the rules:
Given a board with m by n cells, each cell has an initial state live (1) or dead (0). Each cell interacts with its eight neighbors (horizontal, vertical, diagonal) using the following four rules (taken from the above Wikipedia article):
Any live cell with fewer than two live neighbors dies, as if caused by under-population.
Any live cell with two or three live neighbors lives on to the next generation.
Any live cell with more than three live neighbors dies, as if by over-population..
Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
And implementation (https://discuss.leetcode.com/topic/29054/easiest-java-solution-with-explanation):
public void gameOfLife(int[][] board) {
if (board == null || board.length == 0) return;
int m = board.length, n = board[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int lives = liveNeighbors(board, m, n, i, j);
// In the beginning, every 2nd bit is 0;
// So we only need to care about when will the 2nd bit become 1.
if (board[i][j] == 1 && lives >= 2 && lives <= 3) {
board[i][j] = 3; // Make the 2nd bit 1: 01 ---> 11
}
if (board[i][j] == 0 && lives == 3) {
board[i][j] = 2; // Make the 2nd bit 1: 00 ---> 10
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
board[i][j] >>= 1; // Get the 2nd state.
}
}
}
public int liveNeighbors(int[][] board, int m, int n, int i, int j) {
int lives = 0;
for (int x = Math.max(i - 1, 0); x <= Math.min(i + 1, m - 1); x++) {
for (int y = Math.max(j - 1, 0); y <= Math.min(j + 1, n - 1); y++) {
lives += board[x][y] & 1;
}
}
lives -= board[i][j] & 1;
return lives;
}
And driver:
public static void main(String args[]) {
GameOfLife gl = new GameOfLife();
int[][] board = {
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 1, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0}
};
gl.gameOfLife(board);
}
And my question is, what do the x and y in liveNeighbors() represent? Do not understand why the need for Math.min() and Math.max(). And also, does lives represent the amount of initialized lives on the board?
The given code is using the min and max functions to limit the search to valid entries in the array. If this is not done, the code will return an ArrayOutOfBoundsException when trying to use -1, m, or n as array indexes. (The loop doesn't "know" that given a square at the right edge of the map, it shouldn't search for living neighbors further to the right; these functions encode that fact.) x and y are simply the loop control variables which are used to iterate over valid squares surrounding the target square.
As for the lives variable, that's the placeholder to keep count of how many live neighbors have been found by the loops below. You might have guessed this by the fact that it's the return value of the liveNeighbors function.
Let's do an example. We'll call liveNeighbors(board,9,9,0,2), where board is the board given in the driver. Your board has dimensions 9x9, so those are the m and n we pass, and for our example we're investigating the square at 0,2, which is the first entry in the third row (which has a 1 to its right). Great, let's begin.
i=0, so x = Math.max(i - 1, 0) = Math.max(-1, 0) = 0 (this shows the reason for the max function: if we just said int x=i-1, we would end up with x = -1 which is out of the bounds of the array. Next we evaluate x <= Math.min(i + 1, m - 1) = Math.min(1, 8) = 1. If we were investigating a cell in the final column, this condition would have enforced the right edge of the array.
I'll leave the similar logic involving y and j to you.
The loop simplifies to:
for (int x = 0; x <= 1; x++) {
for (int y = 1; y <= 3; y++) {
lives += board[x][y] & 1;
}
}
The inner loop will run six times, with the following (x,y) pairs: (0,1),(0,2),(0,3),(1,1),(1,2),(1,3). Convince yourself that these are the neighbors of the square we're investigating, as well as the square itself.
Five of these six squares will return 0, with the one at (1,2) returning 1, so at the end of this loop, lives will equal 1. The final thing to do is lives -= board[i][j] & 1;, which reduces lives by 1 if the square we're investigating has a 1 in it. In our case it doesn't (board[i][j] = 0) so we subtract 0, leaving us with 1, which we return. liveNeighbors(board,9,9,0,2) = 1
I may have gotten x and y backwards once or twice, but hopefully that's enough so you can understand what's going on.
I am struggling with this problem where I have to take (i/2)+1 numbers from one array and then insert them into that back of a second array.
e.g. 1st array = {2, 5, 3, 4, 8, 9}
2nd array = {-1, -1, -1, -1, -1, -1, -1}
what i want to achieve = {-1, -1, -1, 4, 3, 5, 2}
So I want to take the 1st number in the 1st array and insert it into the last position of the 2nd array replacing the -1 and so on and so forth
What I have so far is:
for(int i = 2nd Array.length; i <2nd Array.length; i--){
int value = 1st Array[i];
2nd Array[i]= 2nd Array[i].replace(i, value);
}
for the moment i'm just trying to get it to insert one set of values into the array.
I have not attempted taking only (1st Array.length/2)+1 numbers from the array.
Can anyone give me some advice on how to do this?
For clarity, use one index for each array, i1 index for array1 and i2 for array2.
Assuming both arrays are already initialised:
int i2 = array2.length-1;
for (int i1 = 0; i1 < (array1.length/2+1) && i2 >=0 ; i1++) {
array2[i2] = array1[i1];
i2--;
}
Or you can put everything in the for:
int[] array1 = {1,2,3,4,5,6,7,8,9};
int[] array2 = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
for (int i1 = 0, i2 = array2.length-1;
i1 < (array1.length/2+1) && i2 >=0 ;
i1++, i2--) {
array2[i2] = array1[i1];
}
System.out.println(Arrays.toString(array2));
Output:
[-1, -1, -1, -1, 5, 4, 3, 2, 1]
EDIT
If you want the otherway, just change the direction for index i1, e.g.
for (int i1 = array1.length/2+1, i2 = array2.length-1;
i1 >= 0 && i2 >=0 ;
i1--, i2--) {
array2[i2] = array1[i1];
}
System.out.println(Arrays.toString(array2));
Output:
[-1, -1, -1, 1, 2, 3, 4, 5, 6]
I think there is an problem in your "for" loop.
for(int i = 2nd Array.length; i <2nd Array.length; i--)
It will exit the loop because "i" starts from 2nd Array.length and it will not be less than 2nd Array.length.
to start in the middle of the array, you should set the initial value for i as (length/2 + 1), since arrays indexes starts on 0, you can use array2.length/2
for(int i = array2.length/2; i < array2.length; i++)
array1[i] = array2[i];
I am really stuck at this problem.
In this problem, you are given a 2xN board. You need to fill in non-negative numbers in this board in such a way, that:
The sum of all the numbers filled = N
Each of the 2 rows
consist of numbers in non-increasing order
Each of the N
columns consist of numbers in non-increasing order.
In how many ways can this be done, given the number N?
Two ways are considered different if there is a cell in the board which has different numbers.
The output should be the number of ways the matrix can be formed.
The matrix can have repetitive numbers and zero can be used. The matrix should not have increasing numbers but equal numbers can be filled along side each other.
Example:
input-> 5
output->16
From your example (input=5, output=16) I suppose only integer numbers are allowed.
One naive (brute force) solution is to use backtracing algorithm:
http://en.wikipedia.org/wiki/Backtracking
On this site you can see example with sudoku board being filled until solution is found.
==
For example:
You have array of integers with size 2N.
For position 0 you take first free number.
If solution is not broken yet you go to position 1 of array.
If solution is broken - stop as cannot back anymore
For position 1 you take next free number.
If solution is not broken you you go to position 2 of array.
If solution is broken you back to previous sten and take next free number.
For position 2...
This is typically done with recursion.
I think, on each position (recursion level) numbers can be taken from pool 0..N.
Try - good luck.
EDIT:
Here is valid solution (using backtracking algo):
private final int N = 5;
// 2 rows in one array [0..N-1, N..2N-1]
private int[] board = new int[2 * N];
// found solution counter
int found = 0;
/*
* this method set next number to current position
* and recursively go to next position.
*/
public void check(int position) {
// if board is complete - check if valid
if (position == 2 * N) {
if (isValid()) {
System.out.println("foun : " + Arrays.toString(board));
found++;
}
return;
}
// if board is not complete - put all numbers (0..N) into current position
// and recursively go to next position
for (int v = 0; v <= N; v++) {
board[position] = v;
// if solution is already broken - step backwards
// see: backtracking algorithms
if (isBroken(position)) {
return;
}
check(position + 1);
}
}
public boolean isValid() {
// condition 1
int sum = 0;
for (int i = 0; i < board.length; i++) {
sum += board[i];
}
if (sum != N) {
return false;
}
// conditin 2
int prev = board[0];
for (int i = 1; i < N; i++) {
if (board[i] > prev) {
return false;
}
prev = board[i];
}
prev = board[N];
for (int i = N + 1; i < 2 * N; i++) {
if (board[i] > prev) {
return false;
}
prev = board[i];
}
// condition 3
for (int i = 0; i < N; i++) {
int top = board[i];
int bottom = board[i + N];
if (top < bottom) {
return false;
}
}
// valid
return true;
}
// simplified version of this method - but correct
public boolean isBroken(int current) {
int sum = 0;
for (int i = 0; i <= current; i++) {
sum += board[i];
}
return sum > N;
}
public void start() {
check(0);
System.out.println("found: " + found);
}
And program output for N = 5:
found : [1, 1, 1, 0, 0, 1, 1, 0, 0, 0]
found : [1, 1, 1, 1, 0, 1, 0, 0, 0, 0]
found : [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
found : [2, 1, 0, 0, 0, 1, 1, 0, 0, 0]
found : [2, 1, 0, 0, 0, 2, 0, 0, 0, 0]
found : [2, 1, 1, 0, 0, 1, 0, 0, 0, 0]
found : [2, 1, 1, 1, 0, 0, 0, 0, 0, 0]
found : [2, 2, 0, 0, 0, 1, 0, 0, 0, 0]
found : [2, 2, 1, 0, 0, 0, 0, 0, 0, 0]
found : [3, 0, 0, 0, 0, 2, 0, 0, 0, 0]
found : [3, 1, 0, 0, 0, 1, 0, 0, 0, 0]
found : [3, 1, 1, 0, 0, 0, 0, 0, 0, 0]
found : [3, 2, 0, 0, 0, 0, 0, 0, 0, 0]
found : [4, 0, 0, 0, 0, 1, 0, 0, 0, 0]
found : [4, 1, 0, 0, 0, 0, 0, 0, 0, 0]
found : [5, 0, 0, 0, 0, 0, 0, 0, 0, 0]
found: 16
I'm almost positive this has a solution in closed form, or its similar to another problem with a solution in closed form. I would do it programmatically with recursion.
So suppose you know a solution for N. You want N+1. So what you should do is take all the solutions for N and see where you can stick an extra 1 in there without breaking any constraints. That is, super impose the N solution(s) on the N+1 board then try in all 2N places to add 1 without breaking constraints. Then store all of them in a set so they will be deduped.
In any case, its similar to http://en.wikipedia.org/wiki/Partition_(number_theory)
Here's a brute force way: since this is a 2xN matrix and the sum of all numbers must be N, the simplest solution is to fill the first row with 1's, and the 2nd row with 0's. Now you will need a recursive algorithm that takes a valid board, and removes 1 from any "free" position and add it to any legal position. That board is also a solution. By "free" I mean a number n at position [i, j] where [i+1, j] <= n - 1 and [i, j + 1] <= n - 1. You then recursively invoke the algorithm on the new boards, and save everything.
All that's left is to deduplicate solutions.
Example of the algorithm on input 5:
Initial solution:
11111
00000
The only "free" number is [0, 4]. Remove 1, the only legal positions are [0, 0] and [0, 1]. This gives you 2 new solutions
21110
00000
and
11110
10000
Now apply same algorithm again on both these solutions. Notice that the 2nd board now has 2 "free" numbers. Repeat until you get to
50000
00000
EDIT: Just had a lot of fun coding this example. Didn't test it, but that's where my head is going:
public void TwoRowBoard()
{
var board = new int[2, N];
//Create initial, simplest solution.
for (int i = 0; i < N; i++)
{
board[0, i] = 1;
}
var solutions = new List<int[,]>();
RecursiveSolve(board, solutions);
}
private void RecursiveSolve(int[,] board, List<int[,]> solutions)
{
var freeNumbers = GetFreeNumbers(board);
foreach (var freeNumber in freeNumbers)
{
board[freeNumber.i, freeNumber.j] -= 1;
var legalPositions = GetLegalPositions(board);
foreach (var legalPosition in legalPositions)
{
var newBoard = Copy(board);
newBoard[legalPosition.i, legalPosition.j] += 1;
solutions.Add(newBoard);
RecursiveSolve(newBoard, solutions);
}
}
}
private List<Coordinates> GetLegalPositions(int[,] board)
{
//Position 0, 0 is always legal.
var results = new List<Coordinates> {new Coordinates {i = 0, j = 0}};
//Row 0
for (int j = 1; j < N; j++)
{
if (board[0, j - 1] > board[0, j])
{
results.Add(new Coordinates{i = 0, j = j});
}
}
//Row 1. Board[1, higher than N/2] are never legal positions.
for (int j = 0; j <= N /2; j++)
{
if (board[1, j - 1] > board[1, j]
&& board[0, j] > board[1, j])
{
results.Add(new Coordinates{i = 1, j = j});
}
}
return results;
}
private List<Coordinates> GetFreeNumbers(int[,] board)
{
var results = new List<Coordinates>();
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < N; j++)
{
if (i == 0 && j == 0)
{
continue;
}
if (i == 0)
{
if (j == N - 1 && board[0, j] > 0)
{
results.Add(new Coordinates {i = 0, j = j});
}
else if (board[0, j] > board[1, j]
&& board[0, j] > board[0, j + 1])
{
results.Add(new Coordinates {i = 0, j = j});
}
}
else
{
if (j > N/2 && board[1, j] > 0)
{
throw new Exception("Don't see how it's possible for board[1, N/2 or higher] to not be 0");
}
if (board[1, j] > board[1, j + 1])
{
results.Add(new Coordinates{i = 1, j = j});
}
}
}
}
return results;
}
public class Coordinates
{
public int i { get; set; }
public int j { get; set; }
}