刷题使我快乐,满脸开心.jpg
- 来源:力扣(LeetCode)
- 链接:https://leetcode.cn/problems/word-search/
- 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题目
给定一个 m x n
二维字符网格 board
和一个字符串单词 word
。如果 word
存在于网格中,返回 true
;否则,返回 false
。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例 1:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
示例 2:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
输出:true
示例 3:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
输出:false
提示:
m == board.length
n = board[i].length
1 <= m, n <= 6
1 <= word.length <= 15
board
和word
仅由大小写英文字母组成
进阶:你可以使用搜索剪枝的技术来优化解决方案,使其在
board
更大的情况下可以更快解决问题?
思路
这道题思路其实挺简单的
遍历找到起点
之后启动搜索- 搜索时,分别
向四个方向找
下一个字符 最后一个字符
依然匹配则找到单词,否则找不到
这个很自然的就是一个回溯
思路,然后离不开的一个优化思路就是进阶中提到的剪枝
- 第一层,自然是字符串是否匹配,不匹配就直接断掉
- 第二层,题中其实给了一个提示,那就是同一单元格的字母
不能重复使用
,这样就可以用一个数组来标识是否搜索过,进行剪枝了
基本上思路就是如此了,直接上代码,细节在注释
代码
func exist(board [][]byte, word string) bool {
m, n := len(board), len(board[0])
// 如果字符总个数都不够,直接false
if m*n < len(word) {
return false
}
// 记录是否已经扫描过,便于剪枝
visit := make([][]bool, m)
for i := range visit {
visit[i] = make([]bool, n)
}
var check func(i, j, k int) bool
check = func(i, j, k int) bool {
// 剪枝1 当前字符不匹配则不用考虑
if board[i][j] != word[k] {
return false
}
// 字符匹配,且已经是最后一个字符,那么单词存在
if k == len(word)-1 {
return true
}
// 剪枝2 校验是否已经遍历过
visit[i][j] = true
// 查看上元素
if 0 <= (i-1) && (i-1) < m && !visit[i-1][j] {
if check(i-1, j, k+1) {
return true
}
}
// 查看下元素
if 0 <= (i+1) && (i+1) < m && !visit[i+1][j] {
if check(i+1, j, k+1) {
return true
}
}
// 查看左元素
if 0 <= (j-1) && (j-1) < n && !visit[i][j-1] {
if check(i, j-1, k+1) {
return true
}
}
// 查看右元素
if 0 <= (j+1) && (j+1) < n && !visit[i][j+1] {
if check(i, j+1, k+1) {
return true
}
}
// 还原访问现场
visit[i][j] = false
return false
}
for i, row := range board {
for j := range row {
if check(i, j, 0) {
return true
}
}
}
return false
}