文章目录
前言
整理力扣刷题思路。
- 语言:python
- 题库:来自neetcode: link
一、预备知识
1.最小生成树
最小生成树 (MST) 是指在一个加权连通图中,找到一个无环的子图,使得这个子图包含了图中的所有节点,并且边的总权重最小。具体来说,MST 是一个连通树,它连接了图中的所有节点,但是没有形成环路,同时它的边的权重之和是最小的。
以下是一些关于 MST 的重要性质:
-
可能的多样性:对于一个有 n 个顶点的图,每个生成树都有 n-1 条边。有时候,图中可能存在多个权重相同的最小生成树。如果图中所有边的权重都相同,那么每个生成树都是最小生成树。
-
唯一性:如果每条边的权重都不同,那么最小生成树是唯一的。这在现实情况下通常成立,例如电信公司铺设电缆的例子,不太可能存在两条完全相同成本的路径。这个性质也适用于生成森林。
2.Prim算法
Prim算法是一种贪心算法,用于在连通的无向图中找到最小生成树(MST)。MST是一个连接了图中所有顶点的树,同时使得树中边的总权重最小。
以下是Prim算法的工作原理和步骤:
- 选择起始顶点:首先,随机选择一个顶点作为MST的起始顶点。
- 迭代直到所有顶点都包含在MST中:
- 寻找连接树顶点和非树顶点的边:在每一步中,找到连接已经包含在MST中的顶点和尚未包含在MST中的顶点的边。
- 选择最小权重的边:从这些边中选择权重最小的边。
- 将选定的边添加到MST中:如果添加这条边不会形成环路,就将这条边和它的另一个顶点添加到MST中。
- 返回MST:当所有顶点都被包含在MST中时,算法结束。
二、解题思路
1.BFS
787.cheapest-flights-within-k-stops
有 n 个城市通过一些航班连接。给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,以价格 pricei 抵达 toi。
现在给定所有的城市和航班,以及出发城市 src 和目的地 dst,你的任务是找到出一条最多经过 k 站中转的路线,使得从 src 到 dst 的 价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出 -1。
link
class Solution:
def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int:
adjacent = [[] for _ in range(n)]
#记录每个城市可到达的地方及花费
for flight in flights:
adjacent[flight[0]].append((flight[1],flight[2]))
#记录从初始位置到每个城市的最小花费,这个列表在剪枝中很重要
cur_prices = [float('inf')]*n
cnt = 0
queue = adjacent[src]
Min = float('inf')
while cnt<=k and queue:
for _ in range(len(queue)):
city,price = queue.pop(0)
if price >= Min:
continue
elif city==dst:
Min = min(price,Min)
else:
for nxt,pri in adjacent[city]:
if pri+price < Min and pri+price < cur_prices[nxt]:
queue.append((nxt,pri+price))
cur_prices[nxt] = pri+price
cnt += 1
return Min if Min<float('inf') else -1
743.network-delay-time
有 n 个网络节点,标记为 1 到 n。
给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。
现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1 。
link
class Solution:
def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
adjacent = [[] for _ in range(n)]
for u,v,w in times:
adjacent[u-1].append((v-1,w))
queue = [(k-1,0)]
#记录传递到每个节点的最短时间
cur_time = [float('inf')]*n
cur_time[k-1] = 0
while queue:
node,time = queue.pop(0)
for nxt,t in adjacent[node]:
if cur_time[nxt] > t+time:
cur_time[nxt] = t+time
queue.append((nxt,t+time))
cur_time = set(cur_time)
#仍为无穷大的节点代表未被传递到
return max(cur_time) if float('inf') not in cur_time else -1
2.DFS
332.reconstruct-itinerary
给你一份航线列表 tickets ,其中 tickets[i] = [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。
所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。
例如,行程 [“JFK”, “LGA”] 与 [“JFK”, “LGB”] 相比就更小,排序更靠前。
假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。
link
class Solution:
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
mapping = collections.defaultdict(list)
for fro,to in tickets:
mapping[fro].append(to)
for fro in mapping:
mapping[fro].sort()
ans = []
def dfs(pos):
while mapping[pos]:
dfs(mapping[pos].pop(0))
ans.insert(0,pos)
dfs('JFK')
return ans
参考:link
3.Prim’s
1584.min-cost-to-connect-all-points
给你一个points 数组,表示 2D 平面上的一些点,其中 points[i] = [xi, yi] 。
连接点 [xi, yi] 和点 [xj, yj] 的费用为它们之间的 曼哈顿距离 :|xi - xj| + |yi - yj| ,其中 |val| 表示 val 的绝对值。
请你返回将所有点连接的最小总费用。只有任意两点之间 有且仅有 一条简单路径时,才认为所有点都已连接。
link
class Solution:
def minCostConnectPoints(self, points: List[List[int]]) -> int:
'''
prim算法的思路是n个点需要n-1条边连接
随机选一个点,将此点加入已访问集合,同时将它与其他未访问点的距离入堆
堆pop出的未访问点作为下一个点,重复上面的操作
这样每次得到的距离都是新的点与已访问点的最小距离
'''
n = len(points)
visited = set()
minH = [[0,0]]
ans = 0
while len(visited)<n:
dist,i = heapq.heappop(minH)
if i in visited:
continue
visited.add(i)
ans += dist
for j in range(n):
if j not in visited:
x1,y1 = points[i]
x2,y2 = points[j]
dist = abs(x1-x2) + abs(y1-y2)
heapq.heappush(minH,[dist,j])
return ans
参考neetcode页面的解说视频
778.swim-in-rising-water
在一个 n x n 的整数矩阵 grid 中,每一个方格的值 grid[i][j] 表示位置 (i, j) 的平台高度。
当开始下雨时,在时间为 t 时,水池中的水位为 t 。你可以从一个平台游向四周相邻的任意一个平台,但是前提是此时水位必须同时淹没这两个平台。假定你可以瞬间移动无限距离,也就是默认在方格内部游动是不耗时的。当然,在你游泳的时候你必须待在坐标方格里面。
你从坐标方格的左上平台 (0,0) 出发。返回 你到达坐标方格的右下平台 (n-1, n-1) 所需的最少时间 。
link
class Solution:
def swimInWater(self, grid: List[List[int]]) -> int:
ans = 0
hp = [[grid[0][0],0,0]]
visited = set((0,0))
while hp:
height,i,j = heapq.heappop(hp)
ans = max(ans,height)
if i==j==len(grid)-1:
return ans
for i1,j1 in [(i-1,j),(i+1,j),(i,j-1),(i,j+1)]:
if 0<=i1<len(grid) and 0<=j1<len(grid) and (i1,j1) not in visited:
visited.add((i,j))
heapq.heappush(hp, [grid[i1][j1],i1,j1])