原题链接
https://leetcode-cn.com/problems/word-search-ii/
原题描述
给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words,找出所有同时在二维网格和字典中出现的单词。
单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
范例1
输入:board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], words = ["oath","pea","eat","rain"]
输出:["eat","oath"]
范例2
输入:board = [["a","b"],["c","d"]], words = ["abcb"]
输出:[]
解答
from collections import defaultdict as dt
class Solution:
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
# 初始化 行,列
m,n = len(board),len(board[0])
# 创建 trie树,根据官方的骚方法
Tree = lambda: dt(Tree)
tree = Tree()
for w in words: reduce(dict.__getitem__,w+"#",tree)
# 初始化返回的list和方向
ret = []
directions = [[0,1],[0,-1],[1,0],[-1,0]]
# 深度搜索
def dfs(used,x,y,dic,now):
if "#" in dic: # 如果dic是末尾字符,即包含"#"字符
ret.append(now) # 结算
del dic["#"] # "某字符":{"#":{}} 中的key="#" 没了,"某字符" 的字典也空了
used.add((x,y)) # 记录已访问过 board上的位置,避免这一次重复访问
for direct in directions:
# 四个方向
new_x = x + direct[0]
new_y = y + direct[1]
# 方向满足条件
if 0 <= new_x < m and 0 <= new_y < n and (new_x,new_y) not in used:
# 检查这个新value是否在dic中
next_val = board[new_x][new_y]
if next_val in dic:
# 那么保存这个value,然后进入到对应这个value的字典
dfs(used,new_x,new_y,dic[next_val],now+next_val)
# 妙处,如果它里面没东西了,例如"#":{}已经被删除了。
# 那么它也没作用了
if not dic[next_val]: del dic[next_val]
# 这一趟结束了,now已经存入ret,可以清除这个(x,y)
used.remove((x,y))
# 从每个节点开始
for i in range(m):
for j in range(n):
curr_val = board[i][j]
if curr_val in tree:
dfs(set(),i,j,tree[curr_val],curr_val)
if not tree[curr_val]: del tree[curr_val]
return ret