二分法
具有单调性 可以用二分查找定位最短时间
动态规划
动态规划要能写出来状态转移方程
并查集
连通性问题 只问结果 不关心怎么连起来的
BFS
DFS
基本模版
python
class Solution:
def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]:
n=len(graph)
ans=[]
def dfs(x,path):
if x==n-1:
ans.append(path.copy())
return
for j in graph[x]:
path.append(j)
dfs(j,path)
path.pop()
dfs(0,[0])
return ans
python
class Solution:
def canReach(self, arr: list[int], start: int) -> bool:
n = len(arr)
vis = [False] * n
def dfs(i: int) -> bool:
if not 0 <= i < n or vis[i]: # 出界,或者之前访问过(没找到)
return False
if arr[i] == 0: # 找到了
return True
vis[i] = True # 避免重复访问
return dfs(i + arr[i]) or dfs(i - arr[i])
return dfs(start)
图论里找连通块、判断是否有环
计算每个连通块的大小
python
def solve(n: int, edges: List[List[int]]) -> List[int]:
# 节点编号从 0 到 n-1
g = [[] for _ in range(n)]
for x, y in edges:
g[x].append(y)
g[y].append(x) # 无向图
vis = [False] * n
def dfs(x: int) -> int:
vis[x] = True # 避免重复访问节点
size = 1
for y in g[x]:
if not vis[y]:
size += dfs(y)
return size
# 计算每个连通块的大小
ans = []
for i, b in enumerate(vis):
if not b: # i 没有访问过
size = dfs(i)
ans.append(size)
return ans
连通块个数
python
class Solution:
def findCircleNum(self, isConnected: List[List[int]]) -> int:
n = len(isConnected)
visited = [False] * n
ans = 0
def dfs(x):
visited[x] = True
for y in range(n):
if isConnected[x][y] == 1 and not visited[y]:
dfs(y)
for i in range(n):
if not visited[i]:
ans += 1
dfs(i)
return ans
统计连通块的点数v和边数e
python
class Solution:
def countCompleteComponents(self, n: int, edges: List[List[int]]) -> int:
g = [[] for _ in range(n)]
for x, y in edges:
g[x].append(y)
g[y].append(x)
vis = [False] * n
def dfs(x: int) -> None:
vis[x] = True
nonlocal v, e
v += 1
e += len(g[x])
for y in g[x]:
if not vis[y]:
dfs(y)
ans = 0
for i, b in enumerate(vis):
if not b:
v = e = 0
dfs(i)
ans += e == v * (v - 1)
return ans
【Dijkstra】单源最短路
邻接矩阵处理双向边/单向边 没有负权数边
关键词:非负 单源 从一个点到另一个点的路径
朴素模版判断是否访问过
python
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
g = [[inf for _ in range(n)] for _ in range(n)] # 邻接矩阵
for x, y, d in times:
g[x - 1][y - 1] = d
dis = [inf] * n
ans = dis[k - 1] = 0
done = [False] * n
while True:
x = -1
for i, ok in enumerate(done):
if not ok and (x < 0 or dis[i] < dis[x]):
x = i
if x < 0:
return ans # 最后一次算出的最短路就是最大的
if dis[x] == inf: # 有节点无法到达
return -1
ans = dis[x] # 求出的最短路会越来越大
done[x] = True # 最短路长度已确定(无法变得更小)
for y, d in enumerate(g[x]):
# 更新 x 的邻居的最短路
dis[y] = min(dis[y], dis[x] + d)
堆优化
稀疏图:边的数量远小于n2n^2n2的图。
最小堆对应的结点首次出堆对应最短路径
python
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
g = [[] for _ in range(n)] # 邻接表
for x, y, d in times:
g[x - 1].append((y - 1, d))
dis = [inf] * n
dis[k - 1] = 0
h = [(0, k - 1)]
while h:
dx, x = heappop(h)
if dx > dis[x]: # x 之前出堆过
continue
for y, d in g[x]:
new_dis = dx + d
if new_dis < dis[y]:
dis[y] = new_dis # 更新 x 的邻居的最短路
heappush(h, (new_dis, y))
mx = max(dis)
return mx if mx < inf else -1