Given a 2D board and a word, find if the word exists in the grid.
The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.
For example,
Given board =
[ ["ABCE"], ["SFCS"], ["ADEE"] ]word =
"ABCCED"
, -> returns
true
,
word =
"SEE"
, -> returns
true
,
word = "ABCB"
, -> returns false
.
题意:给定一个二维字母表和一个单词,在字母表上下左右走,查找对应的单词。在一次匹配中,同一个位置的字母只能使用一次。
分析:递归回溯的方式,将单词的字母作为搜索条件,遍历字母表,并借助一个辅助数组来记录匹配到的位置。
增加辅助数组,用于记录字母表中各个位置的匹配情况,新建辅助数组初始化为0。
在遍历字母表时,假若某点(startX, startY)对应单词的第一个字母,则视从该点开始的搜索为对字母表的一次有效搜索。在搜索单词剩下字母时,对于某点(endX, endY),
1. 如果此时(endX, endY)正好匹配单词的最后一个字母,则搜索到了该单词,当前有效搜索成功结束。
2. 如果此时(endX, endY)匹配的不是单词的最后一个字母,并且在(endX, endY)的四个相邻点,和单词的下一个字母都不匹配,则在单词表中,从起点(startX, startY)开始的匹配失败,需要将辅助数组中(startX, startY), ..., (endX, endY)各个位置复位,当次有效搜索失败结束,需要从字母表的(startX + 1, startY + 1)开始全新的匹配,新的有效搜索开始时,辅助数组的所有值都被复位了。
若(i, j)是对应一个匹配的字母,辅助数组(i, j)位置处做上标记,则在寻找下一个字母的位置时,有前后上下四个方向可以选择:{{0, 1}, {0, -1}, {1, 0}, {-1, 0}},
1. (new_i, new_j)在字母表中,不能超出字母表的范围;
2.(new_i, new_j)对应的字母就是当前要搜索的字母;
3. (new_i, new_j)在当前的匹配中没有使用过。
对于新的位置(new_i, new_j),
1. 如果满足如上条件,那么那就是一个可行的位置,在辅助数据(new_i, new_j)处做上标记,在剩余字母表中搜索单词剩余部分字母
2. 如果不满足如上条件,从本次匹配的起点位置开始,擦除辅助数组中相应点的标记,从字母表中的下一个位置,重新搜索。
public class Solution {
public boolean exist(char[][] board, String word) {
int[][] visited = new int[board.length][board[0].length];
for (int i = 0; i < board.length; ++i) {
for (int j = 0; j < board[0].length; ++j) {
if (board[i][j] == word.charAt(0)) {
visited[i][j] = 1;
if (word.length() == 1) {
return true;
}
if (search(board, i, j, word.substring(1), visited)) {
return true;
}
visited[i][j] = 0; //If the remained match failed , reset the visited item.
}
}
}
return false;
}
private boolean search(char[][] board, int i, int j, String word, int[][] visited) {
//from board[i][j], there exists four choices to choose. A 2D array is defined for this.
int[][] choices = new int [][] {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
for (int k = 0; k < choices.length; ++k) {
int new_i = i + choices[k][0];
int new_j = j + choices[k][1];
if (new_i >= 0 && new_j >= 0 &&
new_i < board.length && new_j < board[0].length &&
visited[new_i][new_j] != 1 &&
board[new_i][new_j] == word.charAt(0)) {
visited[new_i][new_j] = 1;
if (word.length() == 1 || search(board, new_i, new_j, word.substring(1), visited)) {
return true;
}
visited[new_i][new_j] = 0;
}
}
return false;
}
}