单词搜索
给出一个二维字符数组和一个单词,判断单词是否在数组中出现,
单词由相邻单元格的字母连接而成,相邻单元指的是上下左右相邻。同一单元格的字母不能多次使用。
数据范围:
0 < 行长度 <= 100
0 < 列长度 <= 100
0 < 单词长度 <= 1000
回溯/深搜
深度优先搜索,我们定义这样一种搜索顺序,即先枚举单词的起点,然后依次枚举单词的每个字母。在这个过程中需要将已经使用过的字母改成一个特殊字母,以避免重复使用字符。
在主函数中两层循环遍历整个二维数组,找出所有满足等于单词第一个字符的,然后创建一个深搜函数,把这个节点的下标.以及第几个字母传入dfs函数,这个函数用于判断单词是否在二维数组中.
dfs函数的函数头:boolean dfs(String[] board, int i, int j, int pos)
//pos是记录搜索到哪个字母了
函数体:从传入的结点开始向四周搜索(可以借助偏移数组)
同时,对搜索过的坐标进行标记,避免重复搜索
如果满足不越界,没判断过且等于对应单词字符,就递归下一个
所有都满足就返回true,反之返回false
结束条件:搜索到单词的最后一个字符
注意:可以将一些函数中用到的数据定义为全局变量,减少参数传递
时间复杂度:单词起点一共有 n2个,单词的每个字母一共有上下左右四个方向可以选择,但由于不能走回头路,所以除了单词首字母外,仅有三种选择。所以总时间复杂度是 O(n2·3k)。
代码:
import java.util.*;
public class Solution {
int m, n;
int[] dx = {0, 0, 1, -1};//偏移数组
int[] dy = {1, -1, 0, 0};
char[] word = {};
boolean[][] ans;//用于标记是否已经搜索
public boolean exist (String[] board, String _word) {
word = _word.toCharArray();
m = board.length;
n = board[0].length();
ans = new boolean[m][n];
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(word[0] == board[i].charAt(j)) {//遍历所有字母
if(dfs(board, i, j, 0) == true) return true;
}
}
}
return false;
}
public boolean dfs(String[] board, int i, int j, int pos) {
if(pos == word.length-1) {//pos是记录搜索到哪个字母了
return true;
}
ans[i][j] = true;//标记以搜索
for(int a = 0; a < 4; a++) {//上下左右搜索
int x = i + dx[a];
int y = j + dy[a];
if(x < m && x >= 0 && y < n && y >= 0 && !ans[x][y] &&
board[x].charAt(y) == word[pos+1]) {//没搜索过且字母相等
if(dfs(board, x, y, pos+1)) return true;
}
}
ans[i][j] = false;//走到这里说没搜到,更改标记为未搜
return false;
}
}