Leetcode

二分法

具有单调性 可以用二分查找定位最短时间

动态规划

动态规划要能写出来状态转移方程

并查集

连通性问题 只问结果 不关心怎么连起来的

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