拓扑排序+dfs+内向基环树
每个连通块必定有且仅有一个环,且由于每个点的出度均为 11,这样的有向图又叫做内向基环树
class Solution { public int maximumInvitations(int[] favorite) { int n = favorite.length; Map<Integer, Integer> graph = new HashMap<>(); // 正图:i -> favorite[i] Map<Integer, List<Integer>> reGraph = new HashMap<>(); // 反图 int[] inDegree = new int[n]; // 记录入度信息 for (int i = 0; i < n; i++) { graph.put(i, favorite[i]); reGraph.putIfAbsent(favorite[i], new ArrayList<>()); reGraph.get(favorite[i]).add(i); inDegree[favorite[i]]++; } // 拓扑排序进行剪枝处理 Queue<Integer> que = new LinkedList<>(); for (int i = 0; i < n; i++) { if (inDegree[i] == 0) que.offer(i); } while (!que.isEmpty()) { int curr = que.poll(); inDegree[graph.get(curr)]--; if (inDegree[graph.get(curr)] == 0) { que.offer(graph.get(curr)); } } // 根据处理后的入度信息来查找基环 List<List<Integer>> baseCircles = findBaseCircle(favorite, inDegree); boolean[] vis = new boolean[n]; for (int i = 0; i < n; i++) { // 入度大于0,表示在环上; 基环长度为2的时候,不能走这些在环上的点 vis[i] = inDegree[i] > 0; } int sumLength = 0; int max = Integer.MIN_VALUE; for (List<Integer> circle: baseCircles) { if (circle.size() > 2) { max = Math.max(circle.size(), max); } else { // 基环长度为2的时候,沿着反图查找最长路径 sumLength += findLeftOrRightLength(circle.get(0), reGraph, vis) + findLeftOrRightLength(circle.get(1), reGraph, vis); } } return Math.max(max, sumLength); } // 递归寻找最长的路径 private int findLeftOrRightLength(int curr, Map<Integer, List<Integer>> reGraph, boolean[] vis) { List<Integer> nextList = reGraph.get(curr); if (nextList == null) return 1; int max = 0; for (int next: nextList) { if (vis[next]) continue; max = Math.max(max, findLeftOrRightLength(next, reGraph, vis)); } return max + 1; } private List<List<Integer>> findBaseCircle(int[] favorite, int[] inDegree) { int n = favorite.length; List<List<Integer>> baseCircles = new ArrayList<List<Integer>>(); boolean[] vis = new boolean[n]; for (int i = 0; i < n; i++) { // 入度为零 表示已经不在环上,标记为已访问即可 vis[i] = inDegree[i] == 0; } for (int i = 0; i < n; i++) { if (vis[i]) continue; int next = i; List<Integer> baseCircle = new ArrayList<>(); while (!vis[next]) { baseCircle.add(next); vis[next] = true; next = favorite[next]; } baseCircles.add(baseCircle); } return baseCircles; } }
作者:Ryanjie
出处:http://www.cnblogs.com/ryanjan/
本文版权归作者和博客园所有,欢迎转载。转载请在留言板处留言给我,且在文章标明原文链接,谢谢!
如果您觉得本篇博文对您有所收获,觉得我还算用心,请点击右下角的 [推荐],谢谢!