leetcode 802. 找到最终的安全状态 - 有向图找环 - 计算出度- 图反向-数组转置-星号使用-zip函数

特别鸣谢:来自夸夸群的 醉笑陪公看落花@知乎王不懂不懂@知乎
感谢醉笑陪公看落花@知乎 倾囊相授,感谢小伙伴们督促学习,一起进步

相关文章:

802. 找到最终的安全状态

在有向图中,以某个节点为起始节点,从该点出发,每一步沿着图中的一条有向边行走。如果到达的节点是终点(即它没有连出的有向边),则停止。

对于一个起始节点,如果从该节点出发,无论每一步选择沿哪条有向边行走,最后必然在有限步内到达终点,则将该起始节点称作是 安全 的。

返回一个由图中所有安全的起始节点组成的数组作为答案。答案数组中的元素应当按 升序 排列。

该有向图有 n 个节点,按 0 到 n - 1 编号,其中 n 是 graph 的节点数。图以下述形式给出:graph[i] 是编号 j 节点的一个列表,满足 (i, j) 是图的一条有向边。

在这里插入图片描述
输入:graph = [[1,2],[2,3],[5],[0],[5],[],[]]
输出:[2,4,5,6]
解释:示意图如上。

题目分析

找环,能走到环上的节点排除之后,剩下的节点就是安全路径

解法1 -用二进制数表示节点访问情况- 超时

  • cover : 记录路径上使用过的结点
  • circle : 记录经过环的结点
class Solution:
    def eventualSafeNodes(self, graph: List[List[int]]) -> List[int]:
        return solve1(graph)
def solve1(graph):
    N = len(graph)
    circle = 0
    for i in range(N):
        circle |= DFS(graph,0,i,circle)
    return showCover(2**N-1 ^ circle)
#
def DFS(graph,cover,i,circle):
    cover2 = cover | 1 << i
    if (circle | 1<<i )== circle or cover == cover2:return circle|cover
    for j in graph[i]:
        circle |= DFS(graph,cover2,j,circle)
    return circle
'''
打印cover情况
'''
def showCover(cover):
    bicover = bin(cover)[2:]
    bicovers = []
    for j in range(len(bicover)-1,-1,-1):
        if bicover[j] == '1': bicovers.append(len(bicover)-j-1)
    return bicovers

解法2 - 三色标记- 通过

  • 0 未访问
  • 1 访问但是发现节点不安全
  • 2 访问发现结点安全
  • 3 标记为访问

3和1,2 可以合并

主要思想: 某个结点是否安全,要看它的所有后裔是否都是安全的

class Solution:
    def eventualSafeNodes(self, graph: List[List[int]]) -> List[int]:
        return solve5(graph)
def solve5(graph):
    # 出度
    cd = [len(x) for x in graph]
    g = graphReverse(graph)
    q = [x for x in range(len(cd)) if cd[x]==0]
    while q:
        i = q.pop()
        for j in g[i]:
            cd[j]-=1
            if cd[j] == 0:
                q.append(j)
    ans = [i for i in range(len(cd)) if cd[i]==0]
    return ans
'''
狼牙数组转置
'''
def graphReverse(graph):
    # a->b b->a
    # 出度换成入度
    p = [[] for i in range(len(graph))]
    # 遍历了一遍节点和边 n+m
    for i in range(len(graph)):
        for j in graph[i]:
            p[j].append(i)
    return p

二进制位表示节点访问情况

打印访问过的结点

def showCover(cover):
    bicover = bin(cover)[2:]
    bicovers = []
    for j in range(len(bicover)-1,-1,-1):
        if bicover[j] == '1': bicovers.append(len(bicover)-j-1)
    return bicovers

数组转置

狼牙数组(同一维度,长度不固定), 普通二维列表 转置

方法1

def graphReverse(graph):
    p = [[] for i in range(len(graph))]
    # 遍历了一遍节点和边 n+m
    for i in range(len(graph)):
        for j in graph[i]:
            p[j].append(i)
    return p

方法2

def listReverse(graph):
    return [list(y) for y in zip(*graph)]

方法3

def listReverse(graph):
    # return [x for x in map(lambda x:list(x),zip(*graph))]
    # return list(map(list,zip(*graph)))
    return list(map(lambda x:list(x),zip(*graph)))

星号使用

graph = [[1,2],[2,3],[5],[0],[5],[],[]]
zip(*graph) == zip( [1,2],[2,3],[5],[0],[5],[],[] )

unzip 也有同样的用法

* 表示接收一个参数
** 表示接受键值对

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值