-
齐头并进的广度优先遍历
- 另外在
带权图中,有一些专门的算法使用场景:- 带权有向图、且所有权重都非负的单源最短路径问题:使用
Dijkstra算法 - 带权有向图的单源最短路径问题:
Bellman-Ford算法 - 一个图的所有结点对的最短路径问题:
Floy-Warshall算法
- 带权有向图、且所有权重都非负的单源最短路径问题:使用
-
102. 二叉树的层序遍历
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]: ans = [] def bfs(node: Optional[TreeNode]): q = deque([node]) while q: level_size = len(q) current_level = [] for _ in range(level_size): node = q.popleft() current_level.append(node.val) if node.left: q.append(node.left) if node.right: q.append(node.right) ans.append(current_level) if not root: return [] bfs(root) return ans -
323. 无向图中连通分量的数目
class Solution: def countComponents(self, n: int, edges: List[List[int]]) -> int: graph = defaultdict(list) for u, v in edges: graph[u].append(v) graph[v].append(u) inQ = set() def bfs(node: int): q = deque([i]) inQ.add(i) while q: level_size = len(q) for _ in range(level_size): node = q.popleft() for nei in graph[node]: if nei not in inQ: q.append(nei) inQ.add(nei) ans = 0 for i in range(n): if i not in inQ: bfs(i) ans += 1 return ans -
107. 二叉树的层序遍历 II
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]: ans = [] def bfs(node: Optional[TreeNode]): q = deque([node]) while q: level_size = len(q) current_level = [] for _ in range(level_size): node = q.popleft() current_level.append(node.val) if node.left: q.append(node.left) if node.right: q.append(node.right) ans.append(current_level) if not root: return [] bfs(root) return ans[::-1] -
剑指 Offer 32 - I. 从上到下打印二叉树
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def levelOrder(self, root: TreeNode) -> List[int]: if not root: return [] ans = [] def bfs(node: TreeNode): q = deque([node]) while q: level_size = len(q) for _ in range(level_size): node = q.popleft() ans.append(node.val) if node.left: q.append(node.left) if node.right: q.append(node.right) bfs(root) return ans -
剑指 Offer 32 - III. 从上到下打印二叉树 III && 103. 二叉树的锯齿形层序遍历
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def levelOrder(self, root: TreeNode) -> List[List[int]]: if not root: return [] ans = [] def bfs(node: TreeNode): q = deque([node]) while q: level_size = len(q) current_level = [] for _ in range(level_size): node = q.popleft() current_level.append(node.val) if node.left: q.append(node.left) if node.right: q.append(node.right) ans.append(current_level) bfs(root) for i in range(len(ans)): if i % 2: ans[i].reverse() return ans -
429. N 叉树的层序遍历
""" # Definition for a Node. class Node: def __init__(self, val=None, children=None): self.val = val self.children = children """ class Solution: def levelOrder(self, root: 'Node') -> List[List[int]]: if not root: return [] ans = [] def bfs(node: 'Node'): q = deque([node]) while q: level_size = len(q) current_level = [] for _ in range(level_size): node = q.popleft() current_level.append(node.val) for child in node.children: q.append(child) ans.append(current_level) bfs(root) return ans -
993. 二叉树的堂兄弟节点
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def isCousins(self, root: Optional[TreeNode], x: int, y: int) -> bool: parent, depth = {}, {} parent[root.val] = None depth[root.val] = 0 def bfs(node: Optional[TreeNode]): q = deque([node]) while q: level_size = len(q) for _ in range(level_size): node = q.popleft() if node.left: q.append(node.left) parent[node.left.val] = node.val depth[node.left.val] = depth[node.val] + 1 if node.right: q.append(node.right) parent[node.right.val] = node.val depth[node.right.val] = depth[node.val] + 1 bfs(root) return depth[x] == depth[y] and parent[x] != parent[y]
-
二维平面上的搜索问题
-
695. 岛屿的最大面积
class Solution: def maxAreaOfIsland(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) inQ = set() dr = [-1,1,0,0] dc = [0,0,-1,1] def bfs(r: int, c: int) -> int: q = deque([(r, c)]) inQ.add((r, c)) area = 1 while q: level_size = len(q) for _ in range(level_size): r, c = q.popleft() for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and grid[nr][nc]==1 and (nr,nc) not in inQ: q.append((nr, nc)) inQ.add((nr, nc)) area += 1 return area ans = 0 for i in range(m): for j in range(n): if grid[i][j] == 1 and (i,j) not in inQ: area = bfs(i, j) ans = max(ans, area) return ans -
200. 岛屿数量
class Solution: def numIslands(self, grid: List[List[str]]) -> int: m, n = len(grid), len(grid[0]) inQ = set() dr = [-1,1,0,0] dc = [0,0,-1,1] def bfs(r: int, c: int): q = deque([(r, c)]) inQ.add((r, c)) while q: level_size = len(q) for _ in range(level_size): r, c = q.popleft() for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and grid[nr][nc]=="1" and (nr,nc) not in inQ: q.append((nr, nc)) inQ.add((nr, nc)) ans = 0 for i in range(m): for j in range(n): if grid[i][j] == "1" and (i, j) not in inQ: bfs(i, j) ans += 1 return ans -
417. 太平洋大西洋水流问题
class Solution: def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]: m, n = len(heights), len(heights[0]) dr = [0,0,-1,1] dc = [-1,1,0,0] def bfs(r: int, c: int, arr: List[List[int]]): q = deque([(r, c)]) arr[r][c] = 1 while q: level_size = len(q) for _ in range(level_size): r, c = q.popleft() for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and arr[nr][nc] == 0 and heights[nr][nc] >= heights[r][c]: q.append((nr, nc)) arr[nr][nc] = 1 pacific = [[0] * n for _ in range(m)] atlantic = [[0] * n for _ in range(m)] for j in range(n): bfs(0, j, pacific) bfs(m-1, j, atlantic) for i in range(m): bfs(i, 0, pacific) bfs(i, n-1, atlantic) return [[i,j] for i in range(m) for j in range(n) if pacific[i][j] and atlantic[i][j]] -
130. 被围绕的区域
class Solution: def solve(self, board: List[List[str]]) -> None: m, n = len(board), len(board[0]) dr = [-1,1,0,0] dc = [0,0,-1,1] def bfs(r: int, c: int): if board[r][c] != "O": return q = deque([(r, c)]) board[r][c] = "A" while q: level_size = len(q) for _ in range(level_size): r, c = q.popleft() for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and board[nr][nc] == "O": q.append((nr, nc)) board[nr][nc] = "A" for i in range(m): bfs(i, 0) bfs(i, n-1) for j in range(1, n-1): bfs(0, j) bfs(m-1, j) for i in range(m): for j in range(n): if board[i][j] == "A": board[i][j] = "O" elif board[i][j] == "O": board[i][j] = "X" -
934. 最短的桥
class Solution: def shortestBridge(self, grid: List[List[int]]) -> int: # 因为grid中总共只有两座岛,所以把每座岛看成一个set整体即可 # 通过dfs将一座岛的合并到一个set m, n = len(grid), len(grid[0]) set1, set2 = set(), set() dr = [0,0,-1,1] dc = [-1,1,0,0] def dfs(r: int, c: int, s: Set[int]): if not (0<=r<m and 0<=c<n) or (r,c) in s or grid[r][c]==0: return s.add((r, c)) for i in range(4): nr, nc = r + dr[i], c + dc[i] dfs(nr, nc, s) flag = 0 for i in range(m): for j in range(n): if grid[i][j] == 1 and (i,j) not in set1: dfs(i, j, set1) flag = 1 break if flag == 1: break for i in range(m): for j in range(n): if grid[i][j] == 1 and (i,j) not in set1: dfs(i, j, set2) # 然后选出岛屿面积比较小的那个做bfs small, big = (set1, set2) if len(set1) < len(set2) else (set2, set1) def bfs() -> int: q = deque(list(small)) inQ = set(list(small)) step = -1 while q: level_size = len(q) for _ in range(level_size): r, c = q.popleft() if (r, c) in big: return step for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and (nr,nc) not in inQ: q.append((nr,nc)) inQ.add((nr,nc)) step += 1 return step return bfs() -
529. 扫雷游戏
class Solution: def updateBoard(self, board: List[List[str]], click: List[int]) -> List[List[str]]: i, j = click[0], click[1] if board[i][j] == 'M': board[i][j] = 'X' return board m, n = len(board), len(board[0]) dr = [-1,-1,-1,0,0,1,1,1] dc = [-1,0,1,-1,1,-1,0,1] def bfs(r: int, c: int): q = deque([(r, c)]) board[r][c] = 'B' while q: level_size = len(q) for _ in range(level_size): r, c = q.popleft() mineCnt = 0 for i in range(8): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and board[nr][nc] == 'M': mineCnt += 1 if mineCnt > 0: board[r][c] = str(mineCnt) continue for i in range(8): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and board[nr][nc] == 'E': q.append((nr, nc)) board[nr][nc] = 'B' bfs(i, j) return board -
1020. 飞地的数量
class Solution: def numEnclaves(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) dr = [-1,1,0,0] dc = [0,0,-1,1] def bfs(r: int, c: int): if grid[r][c] == 0: return q = deque([(r, c)]) grid[r][c] = 0 while q: level_size = len(q) for _ in range(level_size): r, c = q.popleft() for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and grid[nr][nc] == 1: q.append((nr, nc)) grid[nr][nc] = 0 for i in range(m): bfs(i, 0) bfs(i, n-1) for j in range(1, n-1): bfs(0, j) bfs(m-1, j) ans = 0 for i in range(m): for j in range(n): if grid[i][j] == 1: ans += 1 return ans -
1254. 统计封闭岛屿的数目
class Solution: def closedIsland(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) dr = [-1,1,0,0] dc = [0,0,-1,1] def bfs(r: int, c: int): if grid[r][c] == 1: return q = deque([(r, c)]) grid[r][c] = 1 while q: level_size = len(q) for _ in range(level_size): r, c = q.popleft() for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and grid[nr][nc] == 0: q.append((nr, nc)) grid[nr][nc] = 1 for i in range(m): bfs(i, 0) bfs(i, n-1) for j in range(1, n-1): bfs(0, j) bfs(m-1, j) ans = 0 for i in range(m): for j in range(n): if grid[i][j] == 0: bfs(i, j) ans += 1 return ans -
1034. 边界着色
class Solution: def colorBorder(self, grid: List[List[int]], row: int, col: int, color: int) -> List[List[int]]: m, n = len(grid), len(grid[0]) inQ = set() dr = [-1,1,0,0] dc = [0,0,-1,1] def isBorder(r: int, c: int, originalColor: int) -> bool: if r in [0, m-1] or c in [0, n-1]: return True for i in range(4): nr, nc = r + dr[i], c + dc[i] if (nr, nc) not in inQ and grid[nr][nc] != originalColor: return True return False def bfs(r: int, c: int, originalColor: int): q = deque([(r, c)]) inQ.add((r, c)) while q: level_size = len(q) for _ in range(level_size): r, c = q.popleft() if isBorder(r, c, originalColor): grid[r][c] = color for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and grid[nr][nc] == originalColor and (nr, nc) not in inQ: q.append((nr, nc)) inQ.add((nr, nc)) bfs(row, col, grid[row][col]) return grid -
733. 图像渲染
class Solution: def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]: originalColor = image[sr][sc] if originalColor == color: return image m, n = len(image), len(image[0]) dr = [-1,1,0,0] dc = [0,0,-1,1] def bfs(r: int, c: int): q = deque([(r, c)]) image[r][c] = color while q: level_size = len(q) for _ in range(level_size): r, c = q.popleft() for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and image[nr][nc] == originalColor: q.append((nr, nc)) image[nr][nc] = color bfs(sr, sc) return image -
面试题13. 机器人的运动范围
class Solution: def movingCount(self, m: int, n: int, k: int) -> int: board = [[0] * n for _ in range(m)] for i in range(m): for j in range(n): total = 0 for ch in str(i): total += int(ch) for ch in str(j): total += int(ch) if total <= k: board[i][j] = 1 inQ = set() dr = [-1,1,0,0] dc = [0,0,-1,1] def bfs(r: int, c: int) -> int: if board[r][c] == 0: return 0 q = deque([(r, c)]) inQ.add((r, c)) count = 1 while q: level_size = len(q) for _ in range(level_size): r, c = q.popleft() for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and board[nr][nc] == 1 and (nr, nc) not in inQ: q.append((nr, nc)) inQ.add((nr, nc)) count += 1 return count return bfs(0, 0) -
909. 蛇梯棋
class Solution: def snakesAndLadders(self, board: List[List[int]]) -> int: n = len(board) # 得到下一步的行列 def idx2rc(idx: int) -> (int, int): r, c = (idx - 1) // n, (idx - 1) % n if r % 2 == 1: c = n - 1 - c return n - 1 - r, c def bfs() -> int: q = deque([(1, 0)]) inQ = set([1]) while q: level_size = len(q) for _ in range(level_size): idx, step = q.popleft() if idx == n * n: return step for idx_nxt in range(idx+1, min(idx+6, n*n)+1): r, c = idx2rc(idx_nxt) if board[r][c] > 0: idx_nxt = board[r][c] if idx_nxt not in inQ: q.append((idx_nxt, step + 1)) inQ.add(idx_nxt) return -1 return bfs()
-
抽象成图论问题
-
279. 完全平方数
class Solution: def numSquares(self, n: int) -> int: def bfs() -> int: q = deque([(n, 0)]) inQ = set([n]) while q: level_size = len(q) for _ in range(level_size): num, step = q.popleft() if num == 0: return step targets = [num - i*i for i in range(1, int(num**0.5)+1)] for target in targets: if target not in inQ: q.append((target, step + 1)) inQ.add(target) return -1 return bfs() -
322. 零钱兑换
class Solution: def coinChange(self, coins: List[int], amount: int) -> int: def bfs() -> int: q = deque([(amount, 0)]) inQ = set([amount]) while q: level_size = len(q) for _ in range(level_size): num, step = q.popleft() if num == 0: return step targets = [num - coin for coin in coins if num >= coin] for target in targets: if target not in inQ: q.append((target, step + 1)) inQ.add(target) return -1 return bfs() -
22. 括号生成
class Solution: def generateParenthesis(self, n: int) -> List[str]: ans = [] def bfs(): q = deque([('', n, n)]) while q: level_size = len(q) for _ in range(level_size): # left, right代表剩余的还未使用的左/右括号 s, left, right = q.popleft() if left == right == 0: ans.append(s) if left > 0: q.append((s + '(', left - 1, right)) if right > left: q.append((s + ')', left, right - 1)) bfs() return ans -
690. 员工的重要性
""" # Definition for Employee. class Employee: def __init__(self, id: int, importance: int, subordinates: List[int]): self.id = id self.importance = importance self.subordinates = subordinates """ class Solution: def getImportance(self, employees: List['Employee'], id: int) -> int: emap = {e.id: e for e in employees} def bfs() -> int: ans = 0 q = deque([id]) while q: level_size = len(q) for _ in range(level_size): idx = q.popleft() e = emap[idx] ans += e.importance for sub in e.subordinates: q.append(sub) return ans return bfs() -
365. 水壶问题
class Solution: def canMeasureWater(self, jug1Capacity: int, jug2Capacity: int, targetCapacity: int) -> bool: if jug1Capacity + jug2Capacity < targetCapacity: return False def bfs() -> bool: q = deque([(0, 0)]) inQ = set([(0, 0)]) while q: a, b = q.popleft() if a + b == targetCapacity: return True states = set() # 装满水壶一 states.add((jug1Capacity, b)) # 装满水壶二 states.add((a, jug2Capacity)) # 清空水壶一 states.add((0, b)) # 清空水壶二 states.add((a, 0)) # 从水壶一向另外水壶二倒水,直到装满或者倒空 states.add((min(jug1Capacity, b + a), 0 if b <= jug1Capacity - a else b - (jug1Capacity - a))) # 从水壶二向另外水壶一倒水,直到装满或者倒空 states.add((0 if a + b <= jug2Capacity else a - (jug2Capacity - b), min(b + a, jug2Capacity))) for state in states: if state not in inQ: q.append(state) inQ.add(state) return False return bfs() -
1306. 跳跃游戏 III
class Solution: def canReach(self, arr: List[int], start: int) -> bool: if arr[start] == 0: return True def bfs() -> bool: q = deque([start]) inQ = set([start]) while q: i = q.popleft() for idx in [i + arr[i], i - arr[i]]: if 0 <= idx < len(arr) and idx not in inQ: if arr[idx] == 0: return True q.append(idx) inQ.add(idx) return False return bfs()
-
-
拓扑排序
-
1136. 并行课程
class Solution: def minimumSemesters(self, n: int, relations: List[List[int]]) -> int: inDeg = [0] * (n+1) graph = defaultdict(list) for u, v in relations: inDeg[v] += 1 graph[u].append(v) def bfs() -> int: q = deque([i for i in range(1, n+1) if inDeg[i] == 0]) term = 0 while q: level_size = len(q) term += 1 for _ in range(level_size): node = q.popleft() for nei in graph[node]: inDeg[nei] -= 1 if inDeg[nei] == 0: q.append(nei) return term ans = bfs() if sum(inDeg) > 0: return -1 return ans -
269. 火星词典
class Solution: def alienOrder(self, words: List[str]) -> str: graph = defaultdict(list) inDeg = {c: 0 for c in words[0]} for i in range(len(words) - 1): s, t = words[i], words[i+1] for c in t: inDeg.setdefault(c, 0) for u, v in zip(s, t): if u != v: graph[u].append(v) inDeg[v] += 1 break else: if len(s) > len(t): return "" def bfs() -> List[int]: ans = [] q = deque([u for u, d in inDeg.items() if d == 0]) while q: ans.extend(q) level_size = len(q) for _ in range(level_size): u = q.popleft() for v in graph[u]: inDeg[v] -= 1 if inDeg[v] == 0: q.append(v) return ans ans = bfs() return "".join(ans) if len(ans) == len(inDeg) else "" -
207. 课程表
class Solution: def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: graph = defaultdict(list) inDeg = [0] * numCourses for v, u in prerequisites: graph[u].append(v) inDeg[v] += 1 def bfs() -> int: q = deque([i for i in range(numCourses) if inDeg[i] == 0]) cnt = 0 while q: level_size = len(q) cnt += level_size for _ in range(level_size): u = q.popleft() for v in graph[u]: inDeg[v] -= 1 if inDeg[v] == 0: q.append(v) return cnt return bfs() == numCourses -
210. 课程表 II
class Solution: def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]: graph = defaultdict(list) inDeg = [0] * numCourses for v, u in prerequisites: graph[u].append(v) inDeg[v] += 1 ans = [] def bfs(): q = deque([i for i in range(numCourses) if inDeg[i] == 0]) while q: level_size = len(q) ans.extend(q) for _ in range(level_size): u = q.popleft() for v in graph[u]: inDeg[v] -= 1 if inDeg[v] == 0: q.append(v) bfs() return ans if len(ans) == numCourses else [] -
310. 最小高度树
class Solution: def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]: if n == 1: return [0] graph = defaultdict(list) inDeg = [0] * n for u, v in edges: graph[u].append(v) graph[v].append(u) inDeg[u] += 1 inDeg[v] += 1 # 已知最小树的根节点一定为该路径中的中间节点,且和总个数奇偶性有关 def bfs() -> List[int]: q = deque([i for i, d in enumerate(inDeg) if d == 1]) remainNodes = n while remainNodes > 2: level_szie = len(q) remainNodes -= level_szie for _ in range(level_szie): u = q.popleft() for v in graph[u]: inDeg[v] -= 1 if inDeg[v] == 1: q.append(v) return list(q) return bfs() -
1245. 树的直径
class Solution: def treeDiameter(self, edges: List[List[int]]) -> int: graph = defaultdict(list) for u, v in edges: graph[u].append(v) graph[v].append(u) n = len(edges) + 1 parents = [0] * n def bfs(start: int) -> int: q = deque([start]) inQ = set([start]) while q: level_size = len(q) for _ in range(level_size): u = q.popleft() for v in graph[u]: if v not in inQ: parents[v] = u q.append(v) inQ.add(v) return u u = bfs(0) # 找到与节点 0 最远的节点 u v = bfs(u) # 找到与节点 u 最远的节点 v path = [] parents[u] = -1 while v != -1: path.append(v) v = parents[v] return len(path) - 1 -
802. 找到最终的安全状态
class Solution: def eventualSafeNodes(self, graph: List[List[int]]) -> List[int]: reversedGraph = defaultdict(list) for u, neighbours in enumerate(graph): for v in neighbours: reversedGraph[v].append(u) inDeg = [len(neighbours) for neighbours in graph] def bfs(): q = deque([i for i, d in enumerate(inDeg) if d == 0]) while q: level_size = len(q) for _ in range(level_size): u = q.popleft() for v in reversedGraph[u]: inDeg[v] -= 1 if inDeg[v] == 0: q.append(v) bfs() return [i for i, d in enumerate(inDeg) if d == 0] -
1203. 项目管理
class Solution: def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]: # 为每一个没有所属组的item创建一个新的group for u in range(n): if group[u] == -1: group[u] = m m += 1 # 建立item之间和group之间的先后关系 graph4Items = [[] for _ in range(n)] inDeg4Items = [0] * n graph4Groups = [[] for _ in range(m)] inDeg4Groups = [0] * m for u in range(n): for v in beforeItems[u]: graph4Items[v].append(u) inDeg4Items[u] += 1 if group[u] != group[v]: graph4Groups[group[v]].append(group[u]) inDeg4Groups[group[u]] += 1 # 返回拓扑排序 def bfs(graph: List[int], inDeg: List[int]) -> List[int]: topOrder = [] q = deque([i for i in range(len(graph)) if inDeg[i] == 0]) while q: level_size = len(q) for _ in range(level_size): u = q.popleft() topOrder.append(u) for v in graph[u]: inDeg[v] -= 1 if inDeg[v] == 0: q.append(v) return topOrder if len(topOrder) == len(graph) else [] # 得到item和group各自的拓扑排序 itemOrder = bfs(graph4Items, inDeg4Items) groupOrder = bfs(graph4Groups, inDeg4Groups) if not itemOrder or not groupOrder: return [] # 得到组内的item的拓扑排序 orderWithinGroup = defaultdict(list) for u in itemOrder: orderWithinGroup[group[u]].append(u) # 得到最后组间的拓扑排序 ans = [] for group in groupOrder: ans += orderWithinGroup[group] return ans
-
双向 BFS 与多源 BFS
-
127. 单词接龙
class Solution: def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: wordId = dict() nodeNum = 0 def addWord(word: str): if word not in wordId: nonlocal nodeNum wordId[word] = nodeNum nodeNum += 1 edge = defaultdict(list) def addEdge(word: str): addWord(word) id1 = wordId[word] chars = list(word) for i in range(len(chars)): tmp = chars[i] chars[i] = "*" newWord = "".join(chars) addWord(newWord) id2 = wordId[newWord] edge[id1].append(id2) edge[id2].append(id1) chars[i] = tmp for word in wordList: addEdge(word) addEdge(beginWord) if endWord not in wordId: return 0 # 使用两个同时进行的广搜,每次从两边各扩展一层节点 def bfs() -> int: disBegin = [inf] * nodeNum beginId = wordId[beginWord] disBegin[beginId] = 0 qBegin = deque([beginId]) disEnd = [inf] * nodeNum endId = wordId[endWord] disEnd[endId] = 0 qEnd = deque([endId]) while qBegin or qEnd: qBeginSize = len(qBegin) for _ in range(qBeginSize): u = qBegin.popleft() if disEnd[u] != inf: return (disBegin[u] + disEnd[u])//2 + 1 for v in edge[u]: if disBegin[v] == inf: disBegin[v] = disBegin[u] + 1 qBegin.append(v) qEndSize = len(qEnd) for _ in range(qEndSize): u = qEnd.popleft() if disBegin[u] != inf: return (disBegin[u] + disEnd[u])//2 + 1 for v in edge[u]: if disEnd[v] == inf: disEnd[v] = disEnd[u] + 1 qEnd.append(v) return 0 return bfs() -
994. 腐烂的橘子
class Solution: def orangesRotting(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) dr = [-1,1,0,0] dc = [0,0,-1,1] def bfs() -> int: ans = 0 q = deque([(r, c, 0) for r, row in enumerate(grid) for c, val in enumerate(row) if val == 2]) while q: level_size = len(q) for _ in range(level_size): r, c, ans = q.popleft() for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and grid[nr][nc] == 1: grid[nr][nc] = 2 q.append((nr, nc, ans+1)) return ans ret = bfs() if any(1 in row for row in grid): return -1 return ret -
542. 01 矩阵
class Solution: def updateMatrix(self, mat: List[List[int]]) -> List[List[int]]: m, n = len(mat), len(mat[0]) zeroes_pos = [(i, j) for i in range(m) for j in range(n) if mat[i][j] == 0] dr = [-1,1,0,0] dc = [0,0,-1,1] dist = [[0] * n for _ in range(m)] def bfs() -> int: # 将所有的 0 添加进初始队列中 q = deque(zeroes_pos) inQ = set(zeroes_pos) while q: level_size = len(q) for _ in range(level_size): r, c = q.popleft() for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and (nr, nc) not in inQ: dist[nr][nc] = dist[r][c] + 1 q.append((nr, nc)) inQ.add((nr, nc)) return dist return bfs() -
1162. 地图分析
class Solution: def maxDistance(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) # 将所有陆地网格存入起始数组 landCells = [(i, j, 0) for i in range(m) for j in range(n) if grid[i][j] == 1] if len(landCells) in [0, m*n]: return -1 dr = [1,0,-1,0] dc = [0,-1,0,1] def bfs() -> int: q = deque(landCells) while q: level_size = len(q) for _ in range(level_size): r, c, dis = q.popleft() for i in range(4): nr, nc = r + dr[i], c + dc[i] if 0 <= nr < m and 0 <= nc < n and grid[nr][nc] == 0: # 访问过的位置标记为 1 q.append((nr, nc, dis+1)) grid[nr][nc] = 1 return dis return bfs() -
433. 最小基因变化
class Solution: def minMutation(self, start: str, end: str, bank: List[str]) -> int: bankSet = set(bank) def bfs() -> int: count = 0 q = deque([start]) inQ = set(start) while q: level_size = len(q) for _ in range(level_size): s = q.popleft() if s == end: return count candidates = [] for i, ch in enumerate(s): for c in "ACGT": if c != ch: candidates.append(s[:i] + c + s[i+1:]) for can in candidates: if can in bankSet and can not in inQ: q.append(can) inQ.add(can) count += 1 return -1 return bfs() -
752. 打开转盘锁
class Solution: def openLock(self, deadends: List[str], target: str) -> int: dead = set(deadends) def bfs() -> int: count = 0 q = deque(["0000"]) inQ = set(["0000"]) while q: level_size = len(q) for _ in range(level_size): s = q.popleft() if s == target: return count if s in dead: continue for i in range(4): digit = int(s[i]) for d in (-1, 1): ns = s[:i] + str((digit + d)%10) + s[i+1:] if ns not in inQ: q.append(ns) inQ.add(ns) count += 1 return -1 return bfs() -
773. 滑动谜题
class Solution: # neighbours是相邻位置的编号,按照行优先顺序 NEIGHBORS = [[1,3], [0,2,4], [1,5], [0,4], [1,3,5], [2,4]] def slidingPuzzle(self, board: List[List[int]]) -> int: # 枚举 status 通过一次交换操作得到的状态 def get(status: str) -> Generator[str, None, None]: s = list(status) x = s.index("0") for y in Solution.NEIGHBORS[x]: s[x], s[y] = s[y], s[x] yield "".join(s) s[x], s[y] = s[y], s[x] initial = "".join(str(num) for num in sum(board, [])) if initial == "123450": return 0 def bfs() -> int: q = deque([(initial, 0)]) inQ = set([initial]) while q: level_size = len(q) for _ in range(level_size): status, step = q.popleft() if status == "123450": return step for next_status in get(status): if next_status not in inQ: q.append((next_status, step + 1)) inQ.add(next_status) return -1 return bfs()
-