Python Leetcode网络延迟时间一题多解

网络延迟时间

在这里插入图片描述
典型的单源最短路径问题,解决这种问题的常用方法有优先队列,DFS, BFS, Dijkstra, Bellman-Ford, SPFA, Floyd-Warshall,下面就对该题采用这7种方法进行求解。

先放上各种算法的对比,思路可更清晰。

在这里插入图片描述
使用heap设计优先队列时,需要设计一个visited集合,存储过去处理过的节点;使用普通队列(deque)时,需要设计distence数组,记录源点到当前节点的最小距离。

PriorityQueue

似乎发现优先队列中,使用heapq比使用PriorityQueue效率更高?

另外需要注意的是,设计的visited集合何时add当前处理的节点要注意,不能在while循环中的for循环中去add!!!因为这样会使得在下一轮循环前会对len(visited)进行判断,这样便出错了!而应该在进入for循环之前进行相应的add操作!

from collections import defaultdict
from heapq import *
class Solution:
    def networkDelayTime(self, times, N, K):
        graph = defaultdict(dict)
        for x, y, t in times:
            graph[x][y] = t
        visited = set()
        q, totalTime = [(0, K)], 0
        heapify(q)
        while q:
            t, node = heappop(q)
            if node in visited: continue
            visited.add(node)
            if len(visited) == N: return t
            for cur_node, cur_t in graph[node].items():
                if cur_node not in visited:
                    heappush(q, (t + cur_t, cur_node))
        return -1

DFS求解

distance[node]记录的是最早到达node的时间(最短距离)。
为了加快速度,在访问每个节点时,若传递该信号的时间比已有信号到达的时间长,则我们退出该信号。
该方法可能会超时。

from collections import defaultdict
class Solution:
    def networkDelayTime(self, times, N, K):
        graph = defaultdict(list)
        for u, v, w in times:
            graph[u].append((v, w))
        distance = {node : float('inf') for node in range(1, N + 1)}
        self.DFS(graph, distance, K, 0)
        totalTime = max(distance.values())
        return totalTime if totalTime != float('inf') else -1
    def DFS(self, graph, distance, node, timeSoFar):
        if timeSoFar > distance[node]: # 信号已经到达此节点,所以不需要探索这个节点
            return
        distance[node] = timeSoFar
        for neighbour, time in sorted(graph[node]):
            self.DFS(graph, distance, neighbour, timeSoFar + time)

BFS求解

本质还是Dijkstra算法,都是根据路径更新规则进行选择。该代码其实与Dijkstra一致。

from collections import deque
from collections import defaultdict
class Solution:
    def networkDelayTime(self, times, N, K):
        dic = defaultdict(list)
        for u, v, w in times:
            dic[u].append((v, w))
        q = deque([(K, 0)])
        visited = {K : 0}
        while q:
            curNode, curTime = q.popleft()
            for node, time in dic[curNode]:
                t = curTime + time
                if node not in visited or t < visited[node]:
                    visited[node] = t
                    q.append((node, t))
        return max(visited.values()) if len(visited) == N else -1

Dijkstra

与BFS代码一致!

其实再仔细对比优先队列的代码,Dijkstra代码中的最短路径更新公式即if node not in visited or t < visited[node],优先队列的使用就相当于该作用!

class Solution:
    def networkDelayTime(self, times: List[List[int]], N: int, K: int) -> int:
        weight = collections.defaultdict(dict)
        for u, v, w in times:
            weight[u][v] = w
        heap = [(0, K)]
        dist = {}
        while heap:
            time, u = heapq.heappop(heap)
            if u not in dist:
                dist[u] = time
                for v in weight[u]:
                    heapq.heappush(heap, (dist[u] + weight[u][v], v))
        return max(dist.values()) if len(dist) == N else -1

Bellman-Ford

class Solution:
    def networkDelayTime(self, times, N, K):
        dist = [float('inf')] * N
        dist[K - 1] = 0
        for _ in range(N - 1): # 最多松弛N - 1次达到最优
            for u, v, w in times:
                if dist[u - 1] + w < dist[v - 1]:
                    dist[v - 1] = dist[u - 1] + w
        return max(dist) if max(dist) != float('inf') else -1

SPFA

Bellman-Ford每一次松弛都是随机的,针对这有点,便有了SPFA(Dijkstra也是在这一点上进行改进),它是Bellman-Ford的一种提升算法(队列优化进行松弛,具体可以参考我的上一篇博文讲解)。

from collections import deque
from collections import defaultdict
class Solution:
    def networkDelayTime(self, times, N, K):
        dist = [float('inf')] * N
        dist[K - 1] = 0
        dic = defaultdict(dict)
        for u, v, w in times:
            dic[u - 1][v - 1] = w
        q = deque([K - 1])
        while q:
            node = q.popleft()
            for v in dic.get(node, []):
                if dist[node] + dic[node][v] < dist[v]:
                    dist[v] = dist[node] + dic[node][v]
                    q.append(v)
        return max(dist) if max(dist) != float('inf') else -1

Floyd-Warshall

该算法通常用以解决所有节点对的最短路径,该算法基于这样一个定理:从节点 i 到节点 j,如果存在一条更短的路径话,那么一定是从另一个节点 k 中转而来,即有 d[i][j] = min(d[i][j],d[i][k]+d[k][j]),而d[i][k]和d[k][j]可以用一样的思想去构建,可以看出这是一个动态规划的思想。在构建i、j中,我们通过枚举所有的k值来进行操作。

class Solution:
    def networkDelayTime(self, times, N, K):
        graph = [[float('inf')] * N for _ in range(N)]
        for i, j, v in times:
            graph[i - 1][j - 1] = v
        for i in range(N):
            graph[i][i] = 0
        for k in range(N):
            for i in range(N):
                for j in range(N):
                    graph[i][j] = min(graph[i][j], graph[i][k] + graph[k][j])
        res = max(graph[K - 1])
        return res if res != float('inf') else -1
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值