[拓扑排序] 6135. 图中的最长环

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情

每日刷题 2022.07.31

题目

  • 给你一个 n 个节点的 有向图 ,节点编号为 0 到 n - 1 ,其中每个节点 至多 有一条出边。
  • 图用一个大小为 n 下标从 0 开始的数组 edges 表示,节点 i 到节点 edges[i] 之间有一条有向边。如果节点 i 没有出边,那么 edges[i] == -1 。
  • 请你返回图中的 最长 环,如果没有任何环,请返回 -1 。
  • 一个环指的是起点和终点是 同一个 节点的路径。

示例

  • 示例1

image.png

输入: edges = [3,3,4,2,3]
输出去: 3
解释: 图中的最长环是:2 -> 4 -> 3 -> 2 。
这个环的长度为 3 ,所以返回 3 。
  • 示例2

image.png

输入: edges = [2,-1,3,1]
输出: -1
解释: 图中没有任何环。

提示

  • n == edges.length
  • 2 <= n <= 10^5
  • -1 <= edges[i] < n
  • edges[i] != i

解题思路

  • 初次学习拓扑排序在图论中,一个有向无环图必然存在至少一个拓扑序与之对应,反之亦然
  • 类似的题目802. 找到最终的安全状态,作完本题后,可以再练练这道题。
  • 拓扑排序的实现,是借助BFS的思想。首先先统计有向图中的每个节点的入度,将入度为0的节点放入到队列中;每次从队列中取出一个节点cur,对cur所有相连的节点,入度都-1(等价于:去掉cur与其相连的边),最后将节点cur从队列中删除,再次将图中入度为0的节点加入到队列中,重复以上的操作。直到队列为空。
  • 如果最后队列为空,有向图中的所有的节点都被遍历过,那么该有向图无环,否则存在环。

AC代码

/**
 * @param {number[]} edges
 * @return {number}
 */
var longestCycle = function(edges) {
  // 使用拓扑排序,不是很难,下次也就可以写了,加油
  // 首先统计每个节点,所对应的入度
  let n = edges.length, indeg = new Array(n).fill(0);
  for(let i = 0; i < n; i++) {
    if(edges[i] == -1) continue;
    indeg[edges[i]]++;
  }
  // console.log(indeg)
  // 之后通过拓扑排序将不属于环中的节点排除
  let vis = new Set(), queue = [];
  for(let i = 0; i < n; i++) {
    if(indeg[i] === 0) {
      // 需要存放到队列中
      queue.push(i);
    }
  }
  while(queue.length != 0) {
    // 进行拓扑排序
    let cur = queue.pop(), next = edges[cur];
    indeg[next]--;
    if(indeg[next] == 0) {
      queue.push(next);
    }
  }
  let flag = true;
  indeg.forEach(val => {
    if(val != 0) {
      flag = false;
    }
  })
  if(flag) return -1;
  // console.log(vis)
  // 拓扑排序完成后,所有的非环的节点都被放入到vis数组中
  let max = 0, r = -1;
  for(let i = 0; i < n; i++) {
    if(vis.has(i) || indeg[i] == 0) {
      // 表示不是环中的节点
      continue;
    }
    // 环中的节点
    let ans = dfs(i);
    if(ans > max) {
      max = ans;
      r = i;
    }
  }
  return max;

  function dfs(tar) {
    let q = [tar], cen = 0;
    while(true) {
      let cur = q.pop(), next = edges[cur];
      if(vis.has(next)) {
        // 找到环的头了
        // console.log(vis, cen)
        return cen;
      }
      q.push(next);
      vis.add(next);
      cen++;
    }
  }
};

猜你喜欢

转载自juejin.im/post/7126534772515405838