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.
Related
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;
}
}
I have coded to following program to implement the Four Color Map Theorem (any map can be colored with only 4 colors without any adjacent regions being the same color, in a nutshell) recursively. Everything compiles, but my output gives me erroneous data (-1 for each region's color instead of a value 0-3 for now). My biggest question is why the output is incorrect.
For those wondering, the input file is an adjacency matrix which looks something as follows:
0 1 0 1
1 0 1 0
0 1 0 1
1 0 1 0
Here is my code:
public class FourColorMapThm
{
public static boolean acceptable(int[] map, int[][] matrix, int r, int c)
{
for(int i = 0; i < map.length; i++)
{
if(matrix[r][i] == 1)
{
if(map[i] == c) return false;
}
}
return true;
}
public static boolean colorTheMap(int[] map, int[][] matrix, int r, int c)
{
boolean q = false;
int i = 0;
if(!acceptable(map, matrix, r, i)) return false;
map[r] = i;
boolean done = true;
for(int j = 0; j < map.length; j++)
{
if(map[j] == -1)
{
done = false;
}
}
if(done) return true;
do
{
i++;
q = colorTheMap(map, matrix, r+1, i);
if(q) return true;
}
while(i <= 3);
map[r] = -1;
return false;
}
public static void main(String[] args) throws IOException
{
Scanner in = new Scanner(System.in);
String snumRegions, fileName;
int numRegions;
System.out.print("Enter the number of regions: ");
snumRegions = in.nextLine();
numRegions = Integer.parseInt(snumRegions);
System.out.print("\nEnter filename for adjacency matrix: ");
fileName = in.nextLine();
in.close();
Scanner inFile = new Scanner(new FileReader(fileName));
PrintWriter outFile = new PrintWriter("coloredMap.txt");
int[][] matrix = new int[numRegions][numRegions];
int[] map = new int[numRegions];
//initializing matrix from file
for(int row = 0; row < matrix.length; row++)
{
for(int col = 0; col < matrix.length; col++)
{
matrix[row][col] = inFile.nextInt();
}
}
inFile.close();
//initialize map vals to -1
for(int i = 0; i < map.length; i++)
{
map[i] = -1;
}
colorTheMap(map, matrix, 0, 0);
outFile.println("Region\t\tColor");
for(int i = 0; i < map.length; i++)
{
outFile.println(i+1 + "\t\t" + map[i]);
}
outFile.close();
}
}
You are not using c in colorTheMap, and you probably wanted to.
The reason you're getting a map with all entries -1 is this:
int i = 0;
if(!acceptable(map, matrix, r, i)) return false;
map[r] = i;
.
.
.
do
{
i++;
q = colorTheMap(map, matrix, r+1, i);
if(q) return true;
}
while(i <= 3);
map[r] = -1;
Every call of colorTheMap(map, matrix, r+1, i) returns false the moment it hits
int i = 0;
if(!acceptable(map, matrix, r, i)) return false;
if any of its neighbors was already colored with 0 (since you are never using c, you will always assign 0 to map[r] in map[r] = i; if you reach that line), and so after the return, we immediately return false before assigning any color to r. I assume your input graphs are connected, and so any call of colorTheMap(map, matrix, r, c) either finds a neighbor of r colored with 0 and doesn't even set map[r] to anything else since if(!acceptable(map, matrix, r, i)) return false; will return immediately, or it only receives assignments of q = false in
do
{
i++;
q = colorTheMap(map, matrix, r+1, i);
if(q) return true;
}
while(i <= 3);
and undoes the coloring in the line map[r] = -1; that follows the loop.
Another note: I assume you were trying to implement greedy coloring, but that is not optimal, i.e. you may end up with uncolored regions this way. The four color problem is way more intricate than a simple "just color everything with a color none of its neighbors was assigned and you're good", otherwise it wouldn't have taken more than a century for a proof that four colors suffice to show up. Here is what looks like an outline of a correct algorithm that takes quadratic time (citation in case the link gets lost: Neil Robertson, Daniel P. Sanders, Paul Seymour, and Robin Thomas. 1996. Efficiently four-coloring planar graphs. In Proceedings of the twenty-eighth annual ACM symposium on Theory of Computing (STOC '96). Association for Computing Machinery, New York, NY, USA, 571–575. DOI:https://doi.org/10.1145/237814.238005). It appeared another 20 years after the proof that four coloring planar graphs is always possible.
int [][]a=new int[9][9] //creates a "square" with 81 0's
How do I go about checking if a input (when filling out the array) already exist in the column or row?
For example, for the row 0, how can I make sure I don't get the number 9 two times (for instance, once on row 0, column 0 and second on row 0 column 1)? I can't seem to figure out how to go about this (all I know is that I'll probably need two for loops? and a if statement. I'm not sure how to go about the if statement tho).
public static void main(String[] args)
{
int[][] a = new int[9][9];
boolean areThereDuplicates;
int input = 9; // or any input of course
int row = 0; // or any row
int column = 0;// or any column
areThereDuplicates = checkDuplicates(input, row, column, a);
if (!areThereDuplicates) // if there are no duplicates, input value
a[row][column] = input;
}
public static boolean checkDuplicates(int numChecked, int row, int column, int[][] arr)
{
// checks row
for (int j = 0; j < arr[row].length; j++)
{
if (arr[row][j] == numChecked)
return true;
}
// checks column
for (int k = 0; k < arr.length; k++)
{
if (arr[k][column] == numChecked)
return true;
}
return false;
}
One important thing I wanted to point out is the for loop that checks the column. arr.length does not return 81; rather it returns 9. arr[row].length also returns how many columns there are in the specified row.
Quick draft, not tested but should work:
a[x][y] = newValue; // e.g. 9
return checkDuplicates(x, y, newValue); // returns true if a duplicate is found
public boolean checkDuplicates(int x, int y, int newValue) {
for (int i=0; i<9; i++) {
if (i!=x && a[i][y]==newValue)
return true;
}
for (int i=0; i<9; i++) {
if (i!=y && a[x][i]==newValue)
return true;
}
return false;
}
So im having a bit of problem with my code.. It's suppose to cross check rows and columns for same integers.
this is what i have so far.. but when i run it, it only seems to check the first integer only. (for example the first line of the sudoku board reads. 1 2 2 2 2 2 2 2 2 2) it wont detect the obvious multiple 2's but if i change the input to 1 1 2 2 2 2 2 2 2 the error will come up of multiple 1's in this case. the multiple any suggestions to tweak my loops to make it go through the columns?
public static void validate(final int[][] sudokuBoard) {
int width = sudokuBoard[0].length;
int depth = sudokuBoard.length;
for (int i = 0; i < width; i++) {
int j = i;
int reference = sudokuBoard[i][j];
while (true) {
if ((j >= width) || (j >= depth)) {
break;
}
else if (i == j){
// do nothing
}
else if (j < width) {
int current = sudokuBoard[i][j];
if (current == reference) {
System.out.print("Invalid entry found (width)" + "\n");
System.out.print(current + "\n");
// invalid entry found do something
}
} else if (j < depth) {
// note reversed indexes
int current = sudokuBoard[j][i];
if (current == reference) {
System.out.print("Invalid entry found (depth)" + "\n");
System.out.print(current + "\n");
// invalid entry found do something
}
}
j++;
}
Your code is more complex than it should be. Why put everything in one single function when you could split in several different functions?
public static void Validate(final int[][] sudokuBoard)
{
int width = sudokuBoard[0].length;
int depth = sudokuBoard.length;
for(int i = 0; i < width; i++)
if(!IsValidRow(sudokuBoard, i, width))
{
//Do something - The row has repetitions
}
for(int j = 0; j < height; j++)
if(!IsValidColumn(sudokuBoard, j, width))
{
//Do something - The columns has repetitions
}
}
static bool IsValidRow(int[][] sudokuBoard, int referenceRow, int width)
{
//Compare each value in the row to each other
for(int i = 0; i < width; i++)
{
for(int j = i + 1; j < width; j++)
{
if(sudokuBoard[referenceRow][i] == sudokuBoard[referenceRow][j])
return false
}
}
return true;
}
static bool IsValidColumn(int[][] sudokuBoard, int referenceColumn, int height)
{
//Compare each value in the column to each other
for(int i = 0; i < height; i++)
{
for(int j = i + 1; j < height; j++)
{
if(sudokuBoard[i][referenceColumn] == sudokuBoard[j][referenceColumn])
return false
}
}
return true;
}
That way, your code is much more easily maintainable/readable. This code above hasn't been tested, but it should be about right.
I suggest debugging this code step by step to really understand what's going on, if that's not clear for you.
Given the constraints of sudoku (a row of n cells must contain the numbers 1-n only) you don't need an order n^2 search (per row or column), you can do it order n by keeping a bit array indicating which numbers you've seen. Here's the pseudo-code for checking rows, do the same for columns:
for i in 0 to depth-1 // rows
boolean seen[] = new seen[width];
for j in 0 to width-1 // columns
if seen[board[i][j]-1] == true
duplicate number
else
seen[board[i][j]-1] = true
I would break the functionality into smaller boolean checks. This way, you can validate row by row, column by column, and square by square. For instance
private boolean isValidRow(int[] row) {
// Code here to check for valid row (ie, check for duplicate numbers)
}
private boolean isValidColumn(int[] column) {
// Code here to check for valid column
}
private boolean isValidSquare(int[][] square) {
// Code here to check for valid square
}
Note that rows and columns only need to be passed a 1 dimensional array. Squares are a 2 dimensional array as you need to check a 3x3 area. You can also treat these methods as static as their functionality is independent of the Sudoku board instance.
Edit: A suggestion on row/column/square validation is to use a HashSet. Sets can only have 1 element of a certain value, so you can add elements and look for a failure. For example:
HashSet<Integer> hs = new HashSet<Integer>();
for(int i = 0; i < 9; i++) {
if(!hs.add(integerArray[i])) // HashSet.add returns 'false' if the add fails
// (ie, if the element exists)
return false;
}
return true;
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.