题目:
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例:
board = [ ['A','B','C','E'], ['S','F','C','S'], ['A','D','E','E'] ] 给定 word = "ABCCED", 返回 true. 给定 word = "SEE", 返回 true. 给定 word = "ABCB", 返回 false.
思路:直接看了大神们的思路和代码,原文链接:https://blog.csdn.net/DERRANTCM/article/details/47248121
整个代码使用了回溯的思想,就是迭代加上循环。需要的数据结构包括一个记录是否访问过的数组,一个记录检查到给定字符的哪个位置的数组。首先遍历数组中的每一个元素,对于一个元素检查该元素是否合法,即行列号是否合法,是否被访问过,是否与对应word中的值相等,若这一切条件均满足,则递归调用函数检查上下左右的位置;如果搜索的位置等于字串的长度,说明已经找到找到匹配的了, 如果没有找到路径(hasPath=false)就回溯。
代码:
class Solution {
public boolean exist(char[][] board, String word) { // 【注意我们假定输入的参数都是合法】
// 访问标记矩阵,初始值默认会设置为false
boolean[][] visited = new boolean[board.length][board[0].length];
// 以每一个位置为起点进行搜索,找到一个路径就停止
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (search(board, visited, i, j, word, new int[]{0})) {
return true;
}
}
}
return false;
}
/**
* @param board 字符矩阵
* @param visited 访问标记矩阵
* @param row 访问的行号
* @param col 访问的列号
* @param word 匹配的字符串
* @param idx 匹配的位置,取数组是更新后的值可以被其它引用所见
* @return
*/
private boolean search(char[][] board, boolean[][] visited, int row, int col, String word, int[] idx) {
// 如果搜索的位置等于字串的长度,说明已经找到找到匹配的了
if (idx[0] == word.length()) {
return true;
}
boolean hasPath = false;
// 当前位置合法
if (check(board, visited, row, col, word, idx[0])) {
// 标记位置被访问过
visited[row][col] = true;
idx[0]++;
// 对上,右,下,左四个方向进行搜索
hasPath = search(board, visited, row - 1, col, word, idx ) // 上
|| search(board, visited, row, col + 1, word, idx) // 右
|| search(board, visited, row + 1, col, word, idx) // 下
|| search(board, visited, row, col - 1, word, idx); // 左
// 如果没有找到路径就回溯
if (!hasPath) {
visited[row][col] = false;
idx[0]--;
}
}
return hasPath;
}
/**
* 判定访问的位置是否合法
*
* @param board 字符矩阵
* @param visited 访问标记矩阵
* @param row 访问的行号
* @param col 访问的列号
* @param word 匹配的字符串
* @param idx 匹配的位置
* @return
*/
public boolean check(char[][] board, boolean[][] visited, int row, int col, String word, int idx) {
return row >= 0 && row < board.length // 行号合法
&& col >= 0 && col < board[0].length // 列号合法
&& !visited[row][col] // 没有被访问过
&& board[row][col] == word.charAt(idx);
// 字符相等
}
}
执行最快的的代码:
思路和上面的相同。
class Solution {
int m;
int n;
public boolean exist(char[][] board, String word) {
if (null == board || word == null || word.isEmpty()) {
return false;
}
boolean[][] used = new boolean[board.length][board[0].length];
m = board.length;
n = board[0].length;
char[] charArray = word.toCharArray();
for(int i=0; i<m; i++) {
for(int j=0; j<n;j++) {
if (exist(board, used, charArray, i, j, 0)) {
return true;
}
}
}
return false;
}
private boolean exist(char[][] board, boolean[][] mem, char[] charArray, int i, int j, int index) {
if (index == charArray.length) {
return true;
}
if (i >= m || i < 0) {
return false;
}
if (j >= n || j < 0) {
return false;
}
if (mem[i][j] || board[i][j] != charArray[index]) {
return false;
}
mem[i][j] = true;
// up -> right -> down -> left
boolean found = exist(board, mem, charArray, i - 1, j, index + 1)
|| exist(board, mem, charArray, i, j + 1, index + 1)
|| exist(board, mem, charArray, i + 1, j, index + 1)
|| exist(board, mem, charArray, i, j - 1, index + 1);
// recover
if (!found) mem[i][j] = false;
return found;
}
}