主要内容
- DFS
- backtracking
- BFS: 两种BFS遍历方式
括号生成
思路
DFS + backtracing 代码基本上是模板化的,只需要注意剪枝条件和递归终止条件
代码
class Solution:
# def generateParenthesis(self, n: int) -> List[str]:
def generateParenthesis(self, n):
"""
dfs + backtracking
:param n:
:return:
"""
result = []
def dfs(path, left_num, right_num):
if left_num + right_num == 2 * n:
if left_num == n:
result.append("".join(path))
return
if left_num < n:
dfs(path + ["("], left_num + 1, right_num)
if right_num < left_num:
dfs(path + [")"], left_num, right_num + 1)
return
dfs([], 0, 0)
return result
在每个树行中找最大值
思路
BFS,分层保存数据
代码
class Solution:
# def largestValues(self, root: TreeNode) -> List[int]:
def largestValues(self, root):
"""
BFS, 按照层数更新最大值
:param root:
:return:
"""
result = []
queue = [(0, root)]
while len(queue) > 0:
depth, node = queue.pop(0)
if node is None:
continue
while depth >= len(result):
result.append(-float("inf"))
result[depth] = max(node.val, result[depth])
queue.append((depth+1, node.left))
queue.append((depth+1, node.right))
return result
单词接龙
思路
思路一
本题思路非常简单:由于是搜索最短路径,所以在BFS和DFS中必然使用BFS算法。主要问题在于BFS中的剪枝策略优化,如果不额外进行剪枝优化,大概率会出现超时问题:
- 使用通配符,例如"d*g"来匹配所有首字母和尾字幕分别为d和g的单词,减少遍历量级
- 及时清理需要遍历的分支,将不需要遍历的分支清除(本题中需要及时清除字典中对应key的value)
思路二
由于后续第二题要求重建路径,而思路一中的剪枝过程会导致路径回溯出现异常,因此需要考虑新的BFS方案:逐层扫描,生成对应层的数据
代码
代码一
word_set = set(wordList)
if endWord not in word_set or not endWord or not beginWord or not word_set:
return 0
word_dict = dict()
for word in wordList:
for i in range(len(word)):
key = word[:i] + "*" + word[i+1:]
if key in word_dict:
word_dict[key].append(word)
else:
word_dict[key] = [word]
queue = [(1, beginWord)]
while queue:
num, word = queue.pop(0)
if word == endWord:
return num
if word in word_set:
word_set.remove(word)
for i in range(len(word)):
key = word[:i] + "*" + word[i+1:]
if key not in word_dict:
continue
for new_word in word_dict[key]:
if new_word not in word_set:
continue
else:
queue.append((num+1, new_word))
word_dict[key] = []
return 0
代码二
class Solution:
# def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
def ladderLength(self, beginWord, endWord, wordList):
"""
BFS
剪枝
:param beginWord:
:param endWord:
:param wordList:
:return:
"""
# 另一种bfs实现逻辑
# https://leetcode.com/problems/word-ladder/discuss/352659/Simple-Python-BFS-solution
word_set = set(wordList)
if endWord not in word_set:
return 0
layer = {beginWord}
dist = 1
while len(layer) > 0:
word_set -= layer
next_layer = set()
for word in layer:
for i in range(len(word)):
for ch in "abcdefghijklmnopqrstuvwxyz":
new_word = word[:i] + ch + word[i+1:]
if new_word == endWord:
return dist+1
if new_word not in word_set:
continue
else:
next_layer.add(new_word)
layer = next_layer
dist += 1
return 0
单词接龙 II
思路
衔接上一题的思路二,采用字典存储从子节点到父节点的所有路径,用于后续的路径重建
代码
class Solution:
# def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
def findLadders(self, beginWord, endWord, wordList):
"""
BFS
:param beginWord:
:param endWord:
:param wordList:
:return:
"""
word_set = set(wordList)
layer = {beginWord}
parents = dict()
while len(layer) > 0:
word_set -= layer
next_layer = set()
for word in layer:
for i in range(len(word)):
for ch in "abcdefghijklmnopqrstuvwxyz":
new_word = word[:i] + ch + word[i + 1:]
if new_word not in word_set:
continue
next_layer.add(new_word)
if new_word not in parents:
parents[new_word] = [word]
else:
parents[new_word].append(word)
if endWord in next_layer:
break
layer = next_layer
result = []
def dfs(path):
if path[-1] == beginWord:
result.append(path[::-1])
return
last_word = path[-1]
if last_word not in parents:
return
for word in parents[last_word]:
dfs(path + [word])
dfs([endWord])
return result
岛屿数量
思路
DFS遍历所有能触达的陆地,然后标记为0,统计最外层遍历过陆地的次数
代码
class Solution(object):
def numIslands(self, grid):
"""
:type grid: List[List[str]]
:rtype: int
"""
height = len(grid)
if height == 0:
return 0
width = len(grid[0])
if width == 0:
return 0
def dfs(row, col):
if grid[row][col] == '0':
return
grid[row][col] = '0'
for (i, j) in [(row-1, col), (row+1, col), (row, col-1), (row, col+1)]:
if i < 0 or i >= height:
continue
if j < 0 or j >= width:
continue
dfs(i, j)
num_islands = 0
for i in range(height):
for j in range(width):
if grid[i][j] == '1':
num_islands += 1
dfs(i, j)
return num_islands