Tags——Graph

leetcode 310. Minimum Height Trees

由于一张图最多有两个最小高度树,所以可以这么写:
方法一:
思路很简单,但是比较耗时,先把图遍历一遍,用字典存下每个节点的所有支路;构建节点集合,如果集合的数量大于2,说明要删除一些节点,先从叶节点开始,从集合中删除叶节点的同时,刚刚维护的字典也需要把这些通往叶节点的支路删掉,得到一个简化版的图,删完一遍叶节点之后,s集合的元素如果仍旧大于2,重复继续删。 参考

class Solution:
    def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]:
        import collections
        # defaultdict无需初始化
        d = collections.defaultdict(set) #字典每一个key对应的value是set集合
        for x,y in edges:
            d[x].add(y)  #集合的add操作
            d[y].add(x)
        s = set(range(n)) #构建节点的集合
        while(len(s)>2): # 满足最小生成树的节点个数不可能超过2
            leaves = set(i for i in s if len(d[i])==1)  #只有一条支路的就是叶节点
            s -= leaves
            for i in leaves:  #要删的节点号
                for j in d[i]: 
                    d[j].remove(i)
        return list(s)

方法二:
只改变了一点点,但是代码运行时间提升了很多,在while循环里维护一个tmp集合,每轮更新叶节点。

class Solution:
    def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]:
        import collections
        # defaultdict无需初始化
        d = collections.defaultdict(set) #字典每一个key对应的value是set集合
        for x,y in edges:
            d[x].add(y)  #集合的add操作
            d[y].add(x)
        s = set(range(n))
        leaves = set(i for i in s if len(d[i])==1)  #只有一条支路的就是叶节点
        while(len(s)>2): # 满足最小生成树的节点个数不可能超过2
            tmp = set()        
            s -= leaves
            for i in leaves:  #要删的节点号
                for j in d[i]: 
                    d[j].remove(i)
                    if len(d[j])==1:
                        tmp.add(j)
            leaves = tmp
        return list(s)

leetcode 802. Find Eventual Safe States

分析:何谓安全,首先,只有流入没有流出的肯定是安全的(就是graph里面的空list),其次,只有一个流出分支,且该分支正好流入安全节点,那么该节点也是安全节点。(如果有多个流出分支,其中一个是流向安全节点的不算)
方法一:
先构建两个字典,一个用来存每个节点流出几个分支,一个用来存流入每个节点的分支列表。第二步,维护一个列表,先存入那些没有流入的节点,循环安全节点列表,找到那些只有一个流出分支,且是流入安全节点的节点,也添进安全列表里。该方法耗时 Runtime: 240 ms, faster than 42.53%
参考

class Solution:
    def eventualSafeNodes(self, graph: List[List[int]]) -> List[int]:
        out_degree = collections.defaultdict(int)  # 用来存每个节点流出几个分支(只是一个数字)
        in_nodes = collections.defaultdict(list)  # 用来流入每个节点的分支列表(是一个list)
        n = len(graph)
        queue, res = [], []
        for i in range(n):  #先遍历一遍,构建上述两个dict
            out_degree[i] = len(graph[i])
            if out_degree[i]!=0:
                for j in graph[i]:
                    in_nodes[j].append(i)
            else:
                queue.append(i)
        
        while queue:
            tmp = queue.pop(0)
            res.append(tmp)
            if len(in_nodes[tmp]):
                for i in in_nodes[tmp]:
                    out_degree[i] -= 1
                    if out_degree[i] == 0:
                        queue.append(i)
        return sorted(res)

方法二:
深度优先遍历,维护一个visited数组,长度为节点个数,初始化为0,如果是安全的则为1,不安全为-1。运行时间Runtime: 180 ms, faster than 83.62% 。 参考

class Solution:
    def eventualSafeNodes(self, graph: List[List[int]]) -> List[int]:
        visited = [0] * len(graph)  # 初始化为0,1表示安全,-1表示不安全
        res = []
        for i in range(len(graph)):
            if self.dfs(graph,visited,i):
                res.append(i)
        return res
    
    def dfs(self, graph, visited,i):
        if visited[i]!=0:
            return visited[i] == 1 
        visited[i] = -1           
        for j in graph[i]:
            if not self.dfs(graph,visited,j):
                return False
        visited[i] = 1 
        return True

leetcode 785. Is Graph Bipartite?

先来一个discuss里的算法,思路是创建一个空字典,如果访问过该节点,就将节点加入字典中,通过判断节点是否在字典中,来保证每个节点的graph只访问一次!参考

class Solution:
    def isBipartite(self, graph: List[List[int]]) -> bool:
        visited = {}
        def dfs(i):
            for j in graph[i]:
                if j in visited:
                    if visited[j] == visited[i]:
                        return False
                else:
                    visited[j] = 1 - visited[i]
                    if not dfs(j):
                        return False
            return True
        for i in range(len(graph)):
            if i not in visited:
                visited[i] = 0
            if not dfs(i):
                return False
        return True 

自己的思路:
我是通过设置visit数组来判断是否经过该节点,初始化为0,第一次经过就设置为1,跟它对应的节点设置成-1,耗时更短,依旧使用深度优先遍历。

class Solution:
    def isBipartite(self, graph: List[List[int]]) -> bool:
        visited= [0] * len(graph) # 0表示未访问,1表示集合1,-1表示集合2
        def dfs(i):
            for j in graph[i]:
                if visited[j]:
                    if visited[j] == visited[i]:
                        return False
                else:
                    visited[j] = 0 - visited[i]
                    if not dfs(j):
                        return False
            return True
        for i in range(len(graph)):
            if visited[i] == 0:
                visited[i] = 1
            if not dfs(i):
                return False
        return True

leetcode 399. Evaluate Division

这一题有点没看懂,先把参考答案放在这里,过几天再看一遍! 参考

class Solution:
    def calcEquation(self, equations, values, queries):
        def dfs(x,y,visited):
            if x==y:
                return 1.0
            visited.add(x)
            for n in d[x]:
                if n in visited:
                    continue
                visited.add(n)
                tmp = dfs(n,y,visited)
                if tmp > 0:
                    return tmp * d[x][n]
            return -1.0
                
        d = collections.defaultdict(dict)
        for (a,b), value in zip(equations, values):
            d[a][b] = value
            d[b][a] = 1.0 / value
        
        res = []
        for x,y in queries:
            if x not in d or y not in d:
                res.append(-1.0)
            else:
                res.append(dfs(x,y,set()))
        return res

leetcode 743. Network Delay Time

最短路径问题,迪杰特斯拉算法求解即可,代码参考这里
Runtime: 80 ms, faster than 98.12%

class Solution:
    def networkDelayTime(self, times: List[List[int]], N: int, K: int) -> int:
        from collections import defaultdict
        Q = set(range(N))
        graph = defaultdict(dict)
        for u, v, w in times:
            graph[u-1][v-1] = w
        
        D = [float('Inf')] * N
        D[K-1] = 0
        while len(Q):
            u = None
            for w in Q:
                if u == None or D[w] < D[u]:
                    u = w
            Q.remove(u)
            for w in graph[u]:
                if D[u] + graph[u][w] < D[w]:
                    D[w] = D[u] + graph[u][w]              
        res = max(D)
        return -1 if res == float('Inf') else res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值