Related
I am trying to search for a number in a particular column of a two dimensional array. I tried a few different approach and would like to use stream in Java 8. However, it doesn't seem to be the best performance. Wonder if someone can help?
boolean isInColumn(int col, int number) {
return IntStream.range(0, board.length)
.map(i -> board[i][col])
.filter(num -> num == number )
.findFirst()
.isPresent();
}
trying to search in a block as well. Any hints?
public boolean isInBlock(int row, int col, int number) {
int r = row - row % 3;
int c = col - col % 3;
for (int i = r; i < r + 3; i++) {
for (int j = c; j < c + 3; j++) {
if (board[i][j] == number)
return true;
}
}
return false;
}
the input data is the following array.
public static int[][] PUZZLE = {
{9,0,0,1,0,0,0,0,5},
{0,0,5,0,9,0,2,0,1},
{8,0,0,0,4,0,0,0,0},
{0,0,0,0,8,0,0,0,0},
{0,0,0,7,0,0,0,0,0},
{0,0,0,0,2,6,0,0,9},
{2,0,0,3,0,0,0,0,6},
{0,0,0,2,0,0,9,0,0},
{0,0,1,9,0,4,5,7,0},
};
This 'stream'-version seems a little bit optimzed, but I think searching for a hit in an array will always be faster the old fashioned way, see Java performance tutorial – How fast are the Java 8 streams?
boolean isInColumn(int col, int number) {
return IntStream.range(0, board.length)
.anyMatch(i -> (board[i][col] == number) );
}
I made a short attempt with a parallel stream, but the overhead made it far worse.
I think it would be different if the action wasn't a simple compare...
If it's only about speed for a Sudoku-solver/generator maybe you shouldn't loop at all but write the 9 conditions in one return statement
return board[0,col] == number || board[1,col] == number ...
Since this seems to be Sudoku what you could do is store the data redundantly. Don't only store the numbers in "normally" in a two dimensional array, but also have two-dimensional boolean arrays, where you store whether the row/column/block contains the number.
class Sudoku {
private final int[][] puzzle = new int[9][9];
private final boolean[][] rows = new boolean[9][9];
private final boolean[][] columns = new boolean[9][9];
private final boolean[][] blocks = new boolean[9][9];
public void setCell(int row, in column, int number) {
puzzle[row][column] = number;
rows[row][number - 1] = true;
columns[column][number - 1] = true;
blocks[calcBlockId(row, column)][number - 1] = true;
}
// returns a number (0 - 8) identifying a block
// 0 - 2 is first line, 3 - 5 second line, etc.
private int calcBlockId(int row, int column) {
// Left as an exercise to the reader
}
public boolean isInColumn(int col, int number) {
return columns[col][number - 1];
}
public boolean isInBlock(int row, int column, int number) {
return blocks[calcBlockId(row, column)][number - 1];
}
}
This code searches for an element in a 2d array and returns the coordinates of the first match, if such an element is present, or null otherwise:
public static int[] findElement(int[][] arr, int element) {
return IntStream
// iterate through the indexes
// of the rows of the array
.range(0, arr.length)
// for each row
.mapToObj(i -> {
// look for the element in this row
int j = IntStream
// iterate through the indexes
// of the elements of the row
.range(0, arr[i].length)
// filter a matching element
.filter(el -> arr[i][el] == element)
// take first match
.findFirst().orElse(-1);
// if element is present
if (j >= 0)
// return its coordinates
return new int[]{i, j};
else
// or null otherwise
return null;
})
// take first non-null coordinates, if they are present
.filter(Objects::nonNull).findFirst()
// or null otherwise
.orElse(null);
}
// test
public static void main(String[] args) {
int[][] puzzle = {
{9, 0, 0, 1, 0, 0, 0, 0, 5},
{0, 0, 5, 0, 9, 0, 2, 0, 1},
{8, 0, 0, 0, 4, 0, 0, 0, 0},
{0, 0, 0, 0, 8, 0, 0, 0, 0},
{0, 0, 0, 7, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 2, 6, 0, 0, 9},
{2, 0, 0, 3, 0, 0, 0, 0, 6},
{0, 0, 0, 2, 0, 0, 9, 0, 0},
{0, 0, 1, 9, 0, 4, 5, 7, 0}};
int[] coordinates = findElement(puzzle, 7);
System.out.println(Arrays.toString(coordinates)); // [4, 3]
}
See also:
• Difference between anyMatch and findAny in java 8
• First unique character in a string using LinkedHashMap
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 have an adjacency matrix adj of the form below:
0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0
1 0 0 0 1 0 1 0 0
0 0 0 1 0 1 0 0 0
0 0 1 0 1 0 0 0 1
0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0
This is the adjacency matrix for a maze with rules adj(x,y) = 1 if:
x != y
x is adjacent to y
neither x or y is a wall in the maze
The maze is as below (beside it are the element numbers):
S X E | 1 2 3
O O O | 4 5 6
O X O | 7 8 9
//S = starting position
//E = ending position
//X = wall
I have a DFS algorithm that will display the nodes to traverse from S to E, but it displays unnecessary nodes.
public static void main(String [] args){
int[][] adj = //the adjacency matrix
boolean[] visited = new boolean[adj.length];
int n = adj.length;
int m = 1; //starting position
int o = 3; //ending position
DFS(adjMatrix, visited, n, m, o);
}
public static void DFS(int[][] adj, boolean[] visited, int n, int i, int o){
System.out.print(" " + (i+1));
visited[i]= true;
if (i+1 != o) {
for (int j = 0; j<n;j++){
if(!(visited[j]) && adj[i][j]==1){
DFS(adj, visited, n, j, o);
}
}
}
}
public static void BFS(int[][] adj, boolean[] visited, int n, int i, int o){
queue Q = new queue;
visited[i]= true;
Q.enqueue(i);
while (!Q.isEmpty()) {
//...
}
}
This prints 1 4 5 6 3 9 7. I'm wracking my head around modifying it so that it will only print 1 4 5 6 3.
What have I done wrong here?
There are some major issues with the code, in addition to fixes needed for the DFS algorithm:
You Start and end are wrong: it should be decreased by 1 (because the
indices are 0 based)
Your adjanecy matrix is wrong (it is of size 10X9 - it should be a squared matrix)(edit fixed it)
Your solution should only print elements that are in the path. One way to do it would be to return a List<> (rather than void - that populates all the nodes in the current path. If you reached the destination, create the list, otherwise - return null. Attach elements only when the recursive call returns something that is not null. Code attached
Also note, it prints the nodes in the correct order (and not reversed order)
public static void main(String [] args){
int[][] adj = {
{0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 1, 0, 0, 0},
{1, 0, 0, 0, 1, 0, 1, 0, 0},
{0, 0, 0, 1, 0, 1, 0, 0, 0},
{0, 0, 1, 0, 1, 0, 0, 0, 1},
{0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 1, 0, 0, 0}
};
boolean[] visited = new boolean[adj.length];
int n = adj.length;
int m = 1-1; //starting position
int o = 3-1; //ending position
System.out.println(DFS(adj, visited, n, m, o));
}
public static List<Integer> DFS(int[][] adj, boolean[] visited, int n, int i, int o){
visited[i]= true;
if (i == o) return new LinkedList<Integer>(Arrays.asList(i+1));
for (int j = 0; j<n;j++){
if(!(visited[j]) && adj[i][j]==1){
List<Integer> res = DFS(adj, visited, n, j, o);
if (res != null) {
res.add(0, i+1);
return res;
}
}
}
return null; //no path
}
Will result (as expected) with:
[1, 4, 5, 6, 3]
As a side note, though this solution is complete (will always find a solution if such exists), it is not optimal - it might return a longer solution than the shortest one.
If you want to find the shortest path from source to target, consider switching to a BFS
When you finally reach your destination, the method stack will have the path.
ArrayList<Integer> list = new ArrayList<>(); // this will have your path.
public static boolean DFS(int[][] adj, boolean[] visited, int n, int i, int o){
if(i==o){
list.add(o);
//System.out.println(i);
return true;
}
visited[i]= true;
for (int j = 0; j<n;j++){
if(!(visited[j]) && adj[i][j]==1){
if(DFS(adj, visited, n, j, o)){
list.add(0,j);
//System.out.println(j);
return true;
}
}
}
return false;
}
Try with this code:
public static boolean DFS(int[][] adj, boolean[] visited, int n, int i, int o){
visited[i]= true;
boolean good = false;
if (i+1 != o) {
for (int j = 0; j<n;j++){
if(!(visited[j]) && adj[i][j]==1){
good |= DFS(adj, visited, n, j, o);
}
}
} else {
good = true;
}
if (good) System.out.print(" " + (i+1));
return good;
}
This will print paths in reverse (from end to start) - but it will only print nodes that are part of a good path. If you need to print the path in start-to-end order, you can store it in an array and then print it in reverse:
public static void DFS(int[][] adj, boolean[] visited,
ArrayList<int> path, int n, int i, int o){
visited[i]= true;
if (i+1 != o) {
for (int j = 0; j<n;j++){
if(!(visited[j]) && adj[i][j]==1){
path.add(j);
DFS(adj, visited, n, j, o);
path.remove(path.size()-1);
}
}
} else {
// show path
for (int i : path) {
System.out.print(" " + i);
}
}
}
I was looking at the sudoku code of the "mine" sudoku Android application and I've noticed this code:
selX = Math.min(Math.max(x, 0), 8);
selY = Math.min(Math.max(y, 0), 8);
What does Math.min(Math.max(x, 0), 8) and Math.min(Math.max(y, 0), 8) mean?
Break it down step by step using the docs:
http://docs.oracle.com/javase/7/docs/api/java/lang/Math.html#max(long
max(int a, int b) Returns the greater of two int values.
min(int a, int b) Returns the smaller of two int values.
So Math.min(Math.max(x, 0), 8); breaks down to:
int maximum = Math.max(x,0);
int final = Math.min(maximum,8);
First you take the maximum value of x and 0, so if x < 0, it will be zero.
Next take the minimum of the result and 8, so the maximum value will be 8.
It is about the same as:
int selX = x;
if (selX < 0) selX = 0;
if (selX > 8) selX = 8;
or
int selX = (x < 0) ? 0 : ((x > 8) ? 8 : x);
The first one returns x, if x is between 0 and 8, 0 if x is less than 0, and 8 if x is greater than 8.
The second one works in a similar fashion. So basically you're getting a number back that is guaranteed to be between 0 and 8, inclusive.
The Java Math class describes what the min and max functions do in detail.
Sudoku means 9 x 9 squares. You can index them from 0 to 8. Math.min(Math.max(x, 0), 8) guarantees that you get a number in that range. Is x > 8 then min(x,8) makes it 8. If x < 0 then max(x,0) makes it 0. That's all.
I have to write an algorithm in Java that uses the
divide and conquer technique. Given an array V with n int elements
the algorithm should calculate the number of times that two consecutive
0's appear.
Example :If V = [3, 0, 0, 1, 0, 1, 3, 2, 0, 0, 0, 1, 2], the algorithm should return 3,
Note that 0, 0, 0 corresponds to having 2 pairs of consecutive zeros.
I have written the program as below but when I run it it gives me an ArrayIndexOutOfBoundsException.
What am I doing wrong ?
public class Test {
public static void main(String[] args){
int[] v = {3, 0, 0, 1, 0, 1, 3, 2, 0, 0, 0, 1, 2};
System.out.println(Conta_Zeri_Main(v));
}
public static int Conta_Zeri_Main(int[] v){
if (v.length == 0 || v.length == 1)
return 0;
else
return Conta_Zeri(v, 1, v.length);
}
public static int Conta_Zeri(int[] v, int i, int f){
int m,result,sx,dx;
if (i >= f)
return 0;
else{
m = (i + f)/2;
sx = Conta_Zeri(v, i, m);
dx = Conta_Zeri(v, m+1, f);
result = sx + dx;
if ((v[m] == v[m+1]) && (v[m] == 0))
result++;
return result;
}
}
}
Apart from the anomalies already pointed out,
In your code you do not check if v[m] = v[m+1] = 0. This will miss out some possibilities when the array is partitioned between 2 consecutive zeroes.
Change your if statement to:
if ( (m < v.length - 1 ) && (v[m] == v[m+1]) && (v[m] == 0) )