Leetcode Link: 79. 单词搜索 - 力扣(LeetCode) 79. 单词搜索 - 力扣(LeetCode)
题目
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

解法一
思路:回溯,自己写的有点冗长
本题的重点有两个
- 怎么剪枝
- 只要当前的搜索结果和
word的前几个字母不匹配,就直接返回False
- 只要当前的搜索结果和
- 怎么不重复利用一个位置
- 用一个
set()来保存所有走过的位置,并在回溯的过程中一直维护这个set()
- 用一个
题解:
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
res = []
path = set()
def process(i, j):
if "".join(res) == word:
return True
# 剪枝
if "".join(res) != word[0:len(res)]:
return False
if (i-1, j) not in path and i-1>=0:
path.add((i-1, j))
res.append(board[i-1][j])
if process(i-1, j):
return True
res.pop()
path.remove((i-1, j))
if (i+1, j) not in path and i+1<=len(board)-1:
path.add((i+1, j))
res.append(board[i+1][j])
if process(i+1, j):
return True
res.pop()
path.remove((i+1, j))
if (i, j+1) not in path and j+1<=len(board[0])-1:
path.add((i, j+1))
res.append(board[i][j+1])
if process(i, j+1):
return True
res.pop()
path.remove((i, j+1))
if (i, j-1) not in path and j-1>=0:
path.add((i, j-1))
res.append(board[i][j-1])
if process(i, j-1):
return True
res.pop()
path.remove((i, j-1))
return False
for i in range(len(board)):
for j in range(len(board[0])):
path.add((i,j))
res.append(board[i][j])
if process(i, j):
return True
res.pop()
path.remove((i,j))
return False
这样写的代码有两个缺点
- 决定入口的时候需要在确定入口时维护一次,因为 process 函数里肯定会走,而不会考虑当前输入位
- 代码太长,重复代码太多
代码去冗余 定义一个 direction 保存 4 个可以走的方向,然后遍历这个
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
res = []
path = set()
direc = [(0,1), (1,0), (-1,0), (0, -1)] # 四个方向
def process(i, j):
if "".join(res) == word:
return True
if "".join(res) != word[0:len(res)]:
return False
for d in direc:
next_i = i+d[0]
next_j = j+d[1]
if (next_i, next_j) not in path and 0<=next_i<len(board) and 0<=next_j<len(board[0]):
path.add((next_i, next_j))
res.append(board[next_i][next_j])
if process(next_i, next_j):
return True
res.pop()
path.remove((next_i, next_j))
return False
for i in range(len(board)):
for j in range(len(board[0])):
path.add((i,j))
res.append(board[i][j])
if process(i, j):
return True
res.pop()
path.remove((i,j))
return False 复习时的代码
思路大体一样,本题最重要的是一定要提前剪枝
这个代码是使用矩阵作为set来表示哪些走过了。
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
word = list(word)
path = []
mask = [[0 for _ in range(len(board[0]))] for _ in range(len(board))]
direc = [[1,0], [-1,0], [0,1], [0,-1]]
def bkt(i, j):
if len(path) > len(word) or word[:len(path)] != path:
return False
if word == path:
return True
for d in direc:
next_i = i + d[0]
next_j = j + d[1]
if 0 <= next_i < len(board) and 0 <= next_j < len(board[0]):
if mask[next_i][next_j] == 0:
path.append(board[next_i][next_j])
mask[next_i][next_j] = 1
if bkt(next_i, next_j):
return True
path.pop()
mask[next_i][next_j] = 0
return False
for i in range(len(board)):
for j in range(len(board[0])):
path.append(board[i][j])
mask[i][j] = 1
if bkt(i, j):
return True
path.pop()
mask[i][j] = 0
return False