1 图与 DFS
现在你总共有 n 门课需要选,记为 0 到 n-1。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。
可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。
示例 1:
输入: 4, [[1,0],[2,0],[3,1],[3,2]]
输出: [0,1,2,3] or [0,2,1,3]
解释: 总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。
因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3] 。
思路 拓扑排序问题 先根据给的顺序表建图 再用BFS或者DFS搜索 注意这是一个无环图 如果在遍历过程正形成了环 即代码中 being_visited 为真 直接返回False
class Solution:
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
from collections import defaultdict
graph = defaultdict(list)
for x, y in prerequisites:
graph[y].append(x)
res = []
visited = set()
def dfs(i, being_visited):
if i in being_visited:
return False
if i in visited:
return True
visited.add(i)
being_visited.add(i)
for j in graph[i]:
if not dfs(j, being_visited):
return False
being_visited.remove(i)
res.append(i)
return True
for i in range(numCourses):
if not dfs(i, set()):
return []
return res[::-1]
2 图与BFS
对于一个具有树特征的无向图,我们可选择任何一个节点作为根。图因此可以成为树,在所有可能的树中,具有最小高度的树被称为最小高度树。给出这样的一个图,写出一个函数找到所有的最小高度树并返回他们的根节点。
该图包含 n 个节点,标记为 0 到 n - 1。给定数字 n 和一个无向边 edges 列表(每一个边都是一对标签)。
你可以假设没有重复的边会出现在 edges 中。由于所有的边都是无向边, [0, 1]和 [1, 0] 是相同的,因此不会同时出现在 edges 里。
思路 根据edgs建立双向图之后 可以发现 要求的节点其实是联通节点最多的 所有可以每次找到叶子节点 去除 最后剩下的就是结果
class Solution:
def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]:
from collections import defaultdict
if not edges:
return [0]
graph = defaultdict(list)
for x, y in edges:
graph[x].append(y)
graph[y].append(x)
# 叶子节点
#print(graph)
leaves = [i for i in graph if len(graph[i]) == 1]
while n > 2:
n -= len(leaves)
nxt_leaves = []
for leave in leaves:
# 与叶子节点相连的点找到
tmp = graph[leave].pop()
# 相连的点删去这个叶子节点
graph[tmp].remove(leave)
if len(graph[tmp]) == 1:
nxt_leaves.append(tmp)
leaves = nxt_leaves
return list(leaves)
3Floyd算法 求出任意两点间的最短距离
对于带权重的图 可以用floyd求出任意两点间的最短距离
有 n 个城市,按从 0 到 n-1 编号。给你一个边数组 edges,其中 edges[i] = [fromi, toi, weighti] 代表 fromi 和 toi 两个城市之间的双向加权边,距离阈值是一个整数 distanceThreshold。
返回能通过某些路径到达其他城市数目最少、且路径距离 最大 为 distanceThreshold 的城市。如果有多个这样的城市,则返回编号最大的城市。
注意,连接城市 i 和 j 的路径的距离等于沿该路径的所有边的权重之和。
输入:n = 4, edges = [[0,1,3],[1,2,1],[1,3,4],[2,3,1]], distanceThreshold = 4
输出:3
解释:城市分布图如上。
每个城市阈值距离 distanceThreshold = 4 内的邻居城市分别是:
城市 0 -> [城市 1, 城市 2]
城市 1 -> [城市 0, 城市 2, 城市 3]
城市 2 -> [城市 0, 城市 1, 城市 3]
城市 3 -> [城市 1, 城市 2]
城市 0 和 3 在阈值距离 4 以内都有 2 个邻居城市,但是我们必须返回城市 3,因为它的编号最大。
class Solution:
def findTheCity(self, n: int, edges: List[List[int]], distanceThreshold: int) -> int:
d = [[float("inf") for _ in range(n)] for _ in range(n)] # 建立dp数组,初始化为无穷大
for e in edges:
d[e[0]][e[1]] = d[e[1]][e[0]] = e[2] # 赋权值
for k in range(n):
for i in range(n):
for j in range(n):
d[i][j] = min(d[i][j], d[i][k] + d[k][j])
d[i][i] = 0 # Floyd算法 求出任意两点间的最短距离
#print(d)
res = []
dic = {}
for i in range(n): # 取出距离小于阈值的城市
dic[i] = [d[i][_] for _ in range(n) if 0 < d[i][_] <= distanceThreshold]
#print(i,dic[i])
res.append([i, dic[i]])
res.sort(key=lambda x: (len(x[1]), -x[0])) # 城市个数和ID大小排序
return res[0][0]