【LeetCode & 剑指offer刷题】回溯法与暴力枚举法题2:12 矩阵中的字符串查找(79. Word Search 系列)
【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)
12 矩阵中的字符串查找(79. Word Search 系列)
Word Search
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.
Example:
board =
[
['
A
','
B
','
C
','E'],
['S','F','
C
','S'],
['A','
D
','
E
','E']
]
Given word = "
ABCCED
", return
true
.
Given word = "
SEE
", return
true
.
Given word = "
ABCB
", return
false
.
C++
//字符矩阵中找特定字符串(走水平垂直路线,同一个字符不能用两次)
/*方法:回溯法,递归
空间的改进:可以不用开辟访问矩阵,直接每次用一临时变量保存当前字符,如果访问了,就给board中位置打上非字母标记,如‘#’ '\n'( Remove visited[m][n] completely by modifying board[i][j] = '#' directly.)
如果要取消访问,则将临时变量保存的值再复制回去。
*/
class
Solution
{
private
:
int
m
;
//行数
int
n
;
//列数
public
:
bool
exist
(
vector
<
vector
<
char
>>&
board
,
string word
)
{
m
=
board
.
size
();
n
=
board
[
0
].
size
();
vector
<
vector
<
bool
>>
visited
(
m
,
vector
<
bool
>(
n
,
false
));
//访问矩阵,用于存储元素是否访问的信息
for
(
int
i
=
0
;
i
<
m
;
i
++) //遍历每个元素,可加上是否已经被访问的标记,然后在递归
{
for
(
int
j
=
0
;
j
<
n
;
j
++)
{
if
(
search
(
board
,
visited
,
word
,
i
,
j
,
0
))
{
return
true
;
}
}
}
return
false
;
}
private
:
bool
search
(
vector
<
vector
<
char
>>&
board
,
vector
<
vector
<
bool
>>&
visited
,
string word
,
int
i
,
int
j
,
int
index
) //(i,j)为当前访问坐标,index为扫描单词字符的索引
{
if
(
index
==
word
.
size
())
return
true
;
//所有字符均找到了,递归的总出口之一
//判断当前位置字符是否为要查找的字符
if
(
i
<
0
||
i
>=
m
||
j
<
0
||
j
>=
n
||
board
[i][j] != word[index]
||
visited
[
i
][
j
])
return
false
;
//如果越界或在当前位置没有找到字符,或者该位置已经被访问过了就,就返回false
else
visited
[
i
][
j
]
=
true
;
//说明找到了,打上访问标记
//继续下一步查找,共有4个方向(4个递归分支,一直延伸~)
if
(
search
(
board
,
visited
,
word
,
i
-
1
,
j
,
index
+
1
)
||
search
(
board
,
visited
,
word
,
i
+
1
,
j
,
index
+
1
)
||
search
(
board
,
visited
,
word
,
i
,
j
-
1
,
index
+
1
)
||
search
(
board
,
visited
,
word
,
i
,
j
+
1
,
index
+
1
))
return
true
;
//如果找到了就返回
else
//如果某个结点下一步四个方向均没有找到,则取消当前位置,回溯
{
visited
[
i
][
j
]
=
false
;
//取消访问标记
return
false
;
}
}
};
Word Search II(
hard
,了解即可)
Given a 2D board and a list of words from the dictionary, find all words in the board.
Each word must 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 in a word.
Example:
Input:
words
=
["oath","pea","eat","rain"]
and
board
=
[
['
o
','
a
','a','n'],
['e','
t
','
a
','
e
'],
['i','
h
','k','r'],
['i','f','l','v']
]
Output:
["eat","oath"]
Note:
You may assume that all inputs are consist of lowercase letters
a-z
.
Hint:
You would need to optimize your backtracking to pass the larger test. Could you stop backtracking earlier?
If the current candidate does not exist in all words' prefix
, you could
stop backtracking immediately
. What kind of data structure could answer such query efficiently? Does a hash table work? Why or why not? How about a
Trie
? If you would like to learn how to implement a basic trie, please work on this problem:
Implement Trie (Prefix Tree)
first.(提示:用前缀树提速)
C++
来源:
TstsUgeg的博客
分析:
题目和第79题(
传送门
)相关,第79题找一个单词,通过回溯法能够轻松解决题目,在处理79题时用了isUsed数组来标记每个位置是否已经遍历到,其实是没必要的。具体回溯法的思路就不解释了,相信大家都清楚。
这里要找多个单词,逐个通过回溯法查找效率肯定很低,就不考虑了。题目提示用字典树,解决起来就很方便了,第208题(
传送门
)是设计字典树的题目,不清楚字典树的同学可以先看下。遍历到某个位置时,之前遍历位置组成的字符串如果不是任何待查找字符串的前缀,就可以结束当前递归的分支了。是否是前缀可以通过遍历位置字典树节点指针是否为空来判断,如果为空,表明没有待查找字符串以此为前缀,结束分支,如果不为空可继续深度优先遍历。具体代码: