图——提供并查集或者BFS、DFS的前提

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]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值