题目
方法一-深度优先搜索+剪枝
参考
剪枝指的是在搜索过程中,遇到这条路不可能和目标字符串匹配成功的情况,立即返回,例如该矩阵元素不等于目标字符、该元素已被访问过。
递归参数:
当前元素在矩阵
b
o
a
r
d
board
board 中的行列索引 i 和 j,当前目标字符在
w
o
r
d
word
word 中的索引 k
递归过程:
- 标记当前矩阵元素代表已经访问过,防止重复访问,可以用‘\0’标记
- 向当前元素的上下左右四个方向开展下一层递归,只要找到一条可行路径就直接返回,并记录结果至布尔量 r e s res res
- 还原当前矩阵元素(因为标记访问过的元素只是用来防止当前搜索过程的重复访问,在进行下一次搜索前需要还原矩阵)
终止条件:
- 返回 f a l s e false false:行索引或列索引越界,或者,当前矩阵元素已访问过或与目标字符不同
- 返回 t r u e true true:字符串 w o r d word word 已经全部匹配,即, k = l e n ( w o r d ) − 1 k=len(word)-1 k=len(word)−1
notes:
这里用‘\0’标记访问过的元素,省下了
b
o
o
l
e
a
n
[
]
[
]
v
i
s
i
t
e
d
boolean[][] visited
boolean[][]visited的
O
(
n
2
)
O(n^2)
O(n2)空间开销
class Solution {
boolean dfs(char[][] board, char[] word, int i, int j, int k){
//行索引或列索引越界,或者,当前矩阵元素与目标字符不同,直接返回false
if(i >= board.length || i < 0 || j >= board[0].length ||
j < 0 || board[i][j] != word[k])return false;
//字符串已经全部匹配,直接返回true
if( k == word.length - 1)return true;
//递归过程
board[i][j] = '\0';//标记访问过的矩阵元素
boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) ||
dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i, j - 1, k + 1);
board[i][j] = word[k];//还原当前矩阵元素
return res;
}
public boolean exist(char[][] board, String word) {
char[] words = word.toCharArray();//将目标字符串转换为字符数组
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[0].length; j++){
if(dfs(board, words, i, j, 0))return true;
}
}
return false;
}
}
- 时间复杂度:
O
(
3
K
M
N
)
O(3^KMN)
O(3KMN)
矩阵中共有 MN 个可能的起点,时间复杂度为 O ( M N ) O(MN) O(MN)。搜索过程中每个字符有四个可选择的方向,除去来时的方向(上个字符的方向),剩下3种选择,故最坏情况下,需要遍历矩阵中长度为 K 的字符串的所有方案,时间复杂度为 O ( 3 K ) O(3^K) O(3K)。 - 空间复杂度:
O
(
K
)
O(K)
O(K)
递归深度最大为 K,最坏情况下 K = M N K=MN K=MN