This is the word search problem on leetcode. I've provided a picture below that explains it well. My approach consists of a DFS on each letter in the board (by iterating through a double for loop), I'm doing this so my dfs function can start from each letter and I can get all the different words.
I'm marking the nodes as visited by also passing in a boolean array, where the value is changed to true if I've seen that node and changed back to false if it didn't lead to a path. I think this is where I'm messing up. I'm not sure how to properly mark the nodes as visited here, and if I don't then I get an infinite loop.
When I run my program and print out the strings the dfs is building, I don't get all the possible strings. This is what I'm trying to figure out, how to get all the strings.
You can run the code in leetcode as well. Thank you!
class Solution {
public boolean exist(char[][] board, String word) {
if(board == null || word == null) {
return false;
}
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[i].length; j++) {
List<Character> tempList = new ArrayList<>();
tempList.add(board[i][j]);
boolean[][] tempBoard = new boolean[board.length][board[0].length];
if(wordExists(i, j, word, tempList, board, tempBoard)) {
return true;
}
else{
tempList.remove(tempList.size() - 1);
}
}
}
return false;
}
public static boolean wordExists(int sr, int sc, String word, List<Character> list, char[][] board, boolean[][] tempBoard) {
StringBuilder sb = new StringBuilder();
for(Character c : list) {
sb.append(c);
}
System.out.println(sb.toString());
if(word.equals(sb.toString())) {
return true;
}
final int[][] SHIFTS = {
{0,1},
{1,0},
{0,-1},
{-1,0}
};
tempBoard[sr][sc] = true;
for(int[] shift : SHIFTS) {
int row = sr + shift[0];
int col = sc + shift[1];
if(isValid(board, row, col, tempBoard)) {
list.add(board[row][col]);
if(wordExists(row, col, word, list, board, tempBoard)) {
return true;
}
tempBoard[sr][sc] = false;
list.remove(list.size() - 1);
}
}
return false;
}
public static boolean isValid(char[][] board, int row, int col, boolean[][] tempBoard) {
if(row >= 0 && row < board.length && col >= 0 && col < board[row].length && tempBoard[row][col] != true) {
return true;
}
return false;
}
}
Related
I have to find how many times a given string can be built from a 2D grid of letters:
To build the word, I can start anywhere then move from cell to cell in one of 3 directions:
a) same row, next column (right)
b) next row, same column (down)
c) next row, next column (diagonal right and down)
Example:
char[][] grid = {{'a', 'a'}, {'a', 'a'}};
String str = "aa";
output:
5
Explanation:
a) [0,0][0,1]
b) [0,0][1,0]
c) [1,0][1,1]
d) [0,1][1,1]
e) [0,0][1,1]
This is my code so far:
class Solution {
public boolean exist(char[][] grid, String str) {
int m=grid.length,n=grid[0].length;
boolean[][] visited=new boolean[m][n];
int result = 0;
for (int i=0;i< m;i++){
for (int j=0;j<n;j++){
if (dfs(grid,visited,i,j,0,str)){
result++;
}
}
}
return result;
}
private boolean dfs(char[][] grid, boolean[][] visited, int x, int y, int i, String str){
int m=grid.length,n=grid[0].length;
if (i==str.length()) return true;
if(x<0||x>=m||y<0||y>=n) return false;
if(visited[x][y]) return false;
if(grid[x][y]!=str.charAt(i)) return false;
int[][] dirs={{1,0},{0,1},{1,1}};
visited[x][y]=true;
for (int[] dir: dirs){
int x1=x+dir[0], y1=y+dir[1];
if (dfs(grid, visited, x1, y1, i+1, str)){
return true;
}
}
visited[x][y]=false;
return false;
}
}
For the sample input I mentioned above I am able to get result as 2 instead of 5.
How can I fix this?
Is there any other better approach?
Start at 0,0 work across the columns and down the rows.
Create a method boolean check(String word, int startRow, int startCol, int dRow, int dCol) it will return true if the word is found beginning at startRow,startCol incrementing the column by dCol and the row by dRow after finding each letter. It can return false immediately if the letter being checked doesn't match or if the row or column would be out of bounds.
Call it three times in the loop, first with dRow = 0 and dCol = 1, then with both set to 1, then with dRow = 1 and dCol = 0.
Name your methods better dfs is not a good name.
Here's my version, not exactly as described above. I've decided to return an int rather than a boolean so I can easily add the result to the total. I've hard-coded a grid of letters just to simplify the example.
public class FindWord {
static char [][] grid = {
{'b','a','d'},
{'o','a','k'},
{'d','a','d'}
};
static final int cols = grid[0].length;
static final int rows = grid.length;
public static void main(String[] args) {
countWords("bad");
countWords("dad");
countWords("oak");
countWords("bod");
countWords("bid");
countWords("aaa");
countWords("aa");
countWords("d");
}
private static void countWords(String word) {
int total = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
total += find(word,r,c,0,1) // across
+ find(word,r,c,1,1) // diagonal
+ find(word,r,c,1,0); // down
}
}
System.out.println(total);
}
private static int find(String word, int row, int col, int dRow, int dCol) {
for (char letter : word.toCharArray()) {
if (row >= rows || col >= cols || grid[row][col] != letter)
return 0;
row += dRow;
col += dCol;
}
return 1;
}
}
You might notice that this example has a bug for one letter words. It counts one letter words 3 times because it considers the same starting position as across, diagonal, and down. That is easy to fix with a condition to only check the "across" case and not the other two if the word length is one. I'll leave it to you to make that adjustment.
I need to find out if given adjacency list (int[][]) is describing a strongly connected graph.
I am failing a few test cases with more than 2 nodes in the graph.
for example adjlist = new int[][] {{ 1 },{ 2 },{ 0 },}; meaning that node 0 (first in list) can connect to node 1, node 1 can connect to node 2, and node 2 can connect to node 0.
I tried this:
public boolean allDevicesConnected(int[][] adjlist) {
Boolean[] visited = new Boolean[adjlist.length];
for (int i = 0; i < adjlist.length; i++) {
for (int b = 0; b < visited.length; b++) {
visited[b] = false;
}
DFS1( adjlist, i, visited);
}
for (int j = 0; j < visited.length; j++) {
if (visited[j] == false) {
return false;
}
}
return true;
}
private static void DFS1(int[][] adjlist, int v, Boolean[] visited) {
visited[v] = true;
for (int i = 0; i < adjlist[v].length; i++) {
if (visited[i] == false) {
DFS1(adjlist, i, visited);
}
}
}
any help would be great thanks!!
Your idea to use a depth first search, while marking nodes as visited to determine if strongly connected is a good idea.
The first double for loop is not needed. If the graph is actually strongly connected, it does not matter at which node we start at.
Firstly, I notice that you are doing this in your DFS search:
visited[i] == false
and
DFS1(adjlist, i, visited);
That said, when you did this you are not checking the right node. You should be checking not the index i, but rather the actual value of the node stored at index i.
I edited your code to use this idea:
public boolean allDevicesConnected(int[][] adjlist){
boolean[] marked = new boolean[adjlist.length]; // Default is set to false
DFS_helper(0, adjlist, marked);
for(boolean b : marked)
if(b == false) return false;
return true;
}
public void DFS_helper(int node, int[][] adjlist, boolean[] marked){
marked[node] = true;
for (int i = 0; i < adjList[node].length; i++) {
int dest = adjlist[node][i];
if(marked[dest] == false)
DFS_helper(dest, adjlist, marked);
}
}
I have been trying to figure out my mistake in the Sudoku backtracking solver for three days. The problem is from leetcode Sudoku Solver.
My solver is based on the deduction in the attached picture. The problem is that my board is changed even if a path from root to leaf is invalid.
In other words, after it goes through an invalid path, the values it attempted are fixed in my original board. However, I only update my original board when its children returns true ( see the part in helper method: // put a number and generate children).
Basically, for each '.', I generate all possibilities from 1 to 9, construct a temp board which fills the current '.' with one possibility, then call helper of the next '.' with temp board. I know it is not good to store a same size boardTemp for each possible child because of space cost, but my main concern now is to solve the problem first before optimizing the cost.
All in all, why is my board changing even if all children is not valid?
For example, base on the initial board
..9748...; 7........; .2.1.9...;
..7...24.; .64.1.59.; .98...3..;
...8.3.2.; ........6; ...2759..;
I got the final result after I run:
139748652; 745326189; 826159437;
35769.24.; .64.1.59.; .98...3..;
...8.3.2.; ........6; ...2759..;
public void sudokuSolver(char[][] board) {
for (int i = 0 ; i < board.length ; i++) {
for (int j = 0 ; j < board.length ; j++) {
if (board[i][j] == '.') {
// find the first '.' as root
helper(i, j, board);
return;
}
}
}
}
private boolean helper(int row, int col, char[][] board) {
// case 2. check if it has following '.' and store its position
boolean hasNext = false;
boolean nextSearching = false;
int nextRow = row;
int nextCol = col;
for (int i = 0 ; i < board.length ; i++) {
for (int j = 0; j < board.length ; j++) {
if (nextSearching && !hasNext && board[i][j] == '.') {
hasNext = true; // there is next!
nextRow = i;
nextCol = j;
}
if (i == row && j == col) {
nextSearching = true;
}
}
}
// exit condition: last '.'
if (!hasNext) {
for (char put = '1' ; put <= '9' ; put ++) {
if (isValid(row, col, board, put)) {
return true;
}
}
return false;
}
// put a number and generate children
for (char put = '1' ; put <= '9' ; put ++) {
if (isValid(row, col, board, put)) {
char[][] boardTemp = board;
boardTemp[row][col] = put;
boolean valid = helper(nextRow, nextCol, boardTemp);
if (valid) {
// board is supposed to change only when valid is true.
board[row][col] = put;
return true;
}
}
}
return false;
}
private boolean isValid(int row, int col, char[][] board, char c) {
// go through each row, column, and subblock to determine if c is a valid choice based on current board.
for (int jCol = 0 ; jCol < 9 ; jCol ++) {
if (board[row][jCol] == c) {
return false;
}
}
for (int iRow = 0 ; iRow < 9 ; iRow ++) {
if (board[iRow][col] == c) {
return false;
}
}
for (int i = row/3*3 ; i < row/3*3 + 3 ; i++) {
for (int j = col/3*3 ; j < col/3*3 + 3 ; j++) {
if (board[i][j] == c) {
return false;
}
}
}
return true;
}
There is no difference between using boardTemp and board. char[][] boardTemp = board means they point to the same memory... What you missed in your original code is the else part in after you put an invalid number:
for (char put = '1' ; put <= '9' ; put ++) {
if (isValid(row, col, board, put)) {
char[][] boardTemp = board; // board and boardTemp are essentially the same thing
boardTemp[row][col] = put;
boolean valid = helper(nextRow, nextCol, boardTemp);
if (valid) {
// board is supposed to change only when valid is true.
board[row][col] = put;
return true;
}
// THIS IS WHAT YOU MISSED!!
// if you don't reset the '.' back, your later backtrack will not work
// because you put an invalid number on your board and you will never find a solution
boardTemp[row][col] = '.';
}
}
I am trying to implement an iterative Sudoku solver. To avoid recursion I used a stack, but I'm having problems with its management. The starting board is represented by a String array (variable 'input' in the following code) in which each element is composed of 3 numbers: the [row, col] and its value (i.e, "006" means that the element in the 1st line and 1st col is 6) and is translated into an array of int by the constructor. When I run it, I cannot get a solution, so there are probably mistakes in the nested for cycles. Any help is appreciated.
import java.util.ArrayList;
public class SudokuSolver {
private int[][] matrix = new int[9][9];
private String[] input = { "006", "073", "102", "131", "149", "217",
"235", "303", "345", "361", "378", "422", "465", "514", "521",
"548", "582", "658", "679", "743", "752", "784", "818", "883" };
private ArrayList<int[][]> stack = new ArrayList<>();
public SudokuSolver() {
// Building the board based on input array
for (int n = 0; n < input.length; ++n) {
int i = Integer.parseInt(input[n].substring(0, 1));
int j = Integer.parseInt(input[n].substring(1, 2));
int val = Integer.parseInt(input[n].substring(2, 3));
matrix[i][j] = val;
}
stack.add(matrix);
}
private boolean isSolution(int[][] cells) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if(cells[i][j] == 0)
return false;
}
}
return true;
}
private boolean isValid(int i, int j, int val, int[][] cells) {
for (int k = 0; k < 9; k++)
if (val == cells[k][j])
return false;
for (int k = 0; k < 9; k++)
if (val == cells[i][k])
return false;
return true;
}
private boolean iterativeSudokuSolver() {
int[][] current = null;
while(stack.size() > 0 && !isSolution(stack.get(0))) {
current = stack.remove(0);
for (int row = 0; row < 9; row++) {
for (int col = 0; col < 9; col++) {
if (current[row][col] == 0) {
for (int val = 1; val <= 9; val++) {
if (isValid(row, col, val, current)) {
current[row][col] = val;
stack.add(0, current);
break;
}
}
}
}
}
}
if (current != null && isSolution(current))
return true;
else
return false;
}
public static void main(String [] args) {
SudokuSolver sudokuSolver = new SudokuSolver();
boolean result = sudokuSolver.iterativeSudokuSolver();
if (result)
System.out.println("Sudoku solved");
else
System.out.println("Sudoku not solved");
}
}
A stack implementation by adding and removing the 0-th element of an ArrayList is a very bad idea: it forces the whole content of the array to be shifted back an forth every time. Use LinkedList or modify the end of the list.
When you add and remove the same instance of the matrix back and forth to the stack, it is still the same matrix object, even though you may call it "current" or any other name. This means that when you change something in the matrix and then remove it from your stack, the change stays there (and in every other element of your stack, which are identical links to the same object). The logic of your solution looks like it needs to store the previous state of the solution on the stack, if so - allocate a new array every time and copy the data (also not very efficient, but try starting there).
A good question has to be specific. "Why this doesn't work?" is a bad question. Fix the obvious problems first, debug, and if puzzled provide more information about the state of your program (data in, data on step #1...N, for example)
I'm trying to write a program that takes a Sudoku puzzle and solves it.
However, I'm running into a StackOverflow error at this line:
Move nMove = new Move(current.nextMove(current, sboard).i, current.nextMove(current, sboard).j);
It has a method isLegal that checks for whether the move is valid. If move is valid and the next move is also valid, it adds it to a stack. If it is valid but the next move is not, it should keep searching for a valid number.
Not sure what's causing it.
import java.util.Stack;
public class Board {
Stack<Move> stack = new Stack<Move>();
int boardSize = 9;
public int[][] sboard = {{2,0,0,3,9,5,7,1,6},
{5,7,1,0,2,8,3,0,9},
{9,3,0,7,0,1,0,8,2},
{6,8,2,0,3,9,1,0,4},
{3,5,9,1,7,4,6,2,8},
{7,1,0,8,6,0,9,0,3},
{8,6,0,4,1,7,2,9,5},
{1,9,5,2,8,6,4,3,7},
{4,2,0,0,0,0,8,6,1}};
public Board() {
//for every cell in board:
for (int i = 0; i < boardSize; i++) {
for (int j = 0; j < boardSize; j++) {
//get the value of each cell
int temp = getCell(i,j);
//if cell is empty:
if (temp == 0) {
//print out location of cell
System.out.print ("("+i+", "+j+") ");
//guess values for that cell
solve(i, j);
}
}
}
}
//places a value into specified cell
public void setCell(int value, int row, int col) {
sboard[row][col] = value;
}
//returns value contained at specified cell
public int getCell(int row, int col) {
return sboard[row][col];
}
//if value is legal, continue
public boolean isLegal(int value, int row, int col) {
int r = (row / boardSize) * boardSize;
int c = (col / boardSize) * boardSize;
for (int i = 0; i < boardSize; i++) {
for (int j = 0; j < boardSize; j++) {
if (value == getCell(i, col) || value == getCell(row, j)) {
return false;
}
}
}
return true;
}
//guesses values for empty cells
public boolean solve(int i, int j) {
//set location as current
Move current = new Move(i, j);
Move nMove = new Move(current.nextMove(current, sboard).i, current.nextMove(current, sboard).j);
//guesses values 1 through 9 that are legal
for (int k = 1; k <= 9; k++) {
//if a legal value is found and the next move is possible:
if(isLegal(k, i, j) && solve(nMove.i, nMove.j)) {
//add current to stack
stack.push(current);
//enter the value k into the cell
setCell(k, i, j);
//print new value
System.out.print(sboard[i][j]+"\n");
//return as true
return true;
}
else if (stack.empty()){
}
//if next move is not possible
else if(!solve(nMove.i, nMove.j)){
//remove last "solved" location from stack
stack.pop();
//solve last location again
solve(stack.peek());
}
}
return false;
}
public void solve(Move m) {
solve(m.i, m.j);
}
public static void main(String[] args) {
Board b = new Board();
}
};
class Move {
int i, j;
public Move(int i, int j) {
this.i = i;
this.j = j;
}
public int i() { return i;}
public int j() { return j;}
public Move nextMove(Move current, int[][] sboard){
for (int i = current.i; i < 9; i++) {
for (int j = current.j; j < 9; j++) {
//get the value of each cell
int temp = sboard[i][j];
if (temp == 0) {
return new Move(i, j);
}
}
}
return current;
}
};
For one, it seems redundant to me to have this function in the form current.nextMove(current, board). You can either make this function static, or remove the Move current parameter.
But taking a look at your solve(i, j) function, you essentially have this:
Assume sboard[i][j] = 0 (which it clearly does, in some cases, from your input).
Assume you call solve(i, j).
current will be new Move(i, j).
nMove will then also be new Move(i, j) (since in Move#nextMove,
you essentially say if sboard[i][j] == 0, which it does from step
1).
You will end up calling solve(nMove.i, nMove.j)
Since nMove.i == i and nMove.j == j, you are essentially calling solve(i, j) over again.
Since you're calling the same function with the same parameter, and you're not reaching any base case, you will end up with a stack overflow.
As you have defined an (explicit) stack, you should not call solve() recursively.
Just loop, pop a board, generate all valid next moves, see if one of them is a solution, and if not, push them on the stack.
(I couldn't find where you verify that the board is complete, but I am probably tired.)
Btw, the stack should probably be a Dequeue. I believe a stack is synchronized which slows down the code.