4. 图问题梳理

126 阅读1分钟

参考:

  1. 图论基础及遍历算法
  2. 环检测及拓扑排序算法
  3. 二分图判定算法
  4. 并查集(Union-Find)算法
  5. 众里寻他千百度:名流问题

问题总览

序号题目完成
133. 克隆图

题解

图的遍历

序号题目完成
797. 所有可能的路径
剑指 Offer II 110. 所有路径

797. 所有可能的路径

相同问题:剑指 Offer II 110. 所有路径

class Solution {
    List<List<Integer>> ans;

    public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
        int len = graph.length;
        ans = new ArrayList<>();
        backtrace(graph, 0, new LinkedList<Integer>());
        return ans;
    }

    public void backtrace(int[][] graph, int from, LinkedList<Integer> path) {
        path.add(from);
        if (from == graph.length - 1) {
            ans.add(new ArrayList<>(path));
            path.removeLast();
            return;
        }
        int[] toList = graph[from];
        for (int to : toList) {
            backtrace(graph, to, path);
        }
        path.removeLast();
    }
}

环检测以及拓扑排序

序号题目完成
207. 课程表
210. 课程表 II
剑指 Offer II 113. 课程顺序

207. 课程表

判断节点是否有环。

//DFS解法
class Solution {
    // 是否已经遍历过
    boolean[] visited;
    boolean[] onPath;
    // key为当前节点,value为当前节点能到达的所有节点

    boolean hasCycle = false;

    public boolean canFinish(int numCourses, int[][] prerequisites) {
        visited = new boolean[numCourses];
        onPath = new boolean[numCourses];
        Map<Integer, List<Integer>> paths = new HashMap<>();

        for (int[] prerequisite : prerequisites) {
            //[0,1]表示,要想到达0必须先到达1,那么说明路径是这样的:1->0
            int from = prerequisite[1];
            int to = prerequisite[0];

            List<Integer> availables = paths.getOrDefault(from, new ArrayList<>());
            availables.add(to);
            paths.put(from, availables);
        }

        // 当前
        for (int i = 0; i < numCourses; i++) {
            traverse(paths,i);
        }
        return !hasCycle;
    }

    public void traverse(Map<Integer, List<Integer>> paths, int from) {
        // 如果路径上的节点已经被遍历过,那说明存在环
        if (onPath[from]) {
            hasCycle = true;
            return;
        }

        // 当前节点已经遍历过
        if (visited[from]) {
            return;
        }

        // visited就代表遍历过的节点,不需要再置为false
        visited[from] = true;
        onPath[from] = true;

        List<Integer> availables = paths.get(from);
        if (availables != null && availables.size() > 0) {
            for (int to : availables) {
                traverse(paths, to);
            }
        }
        onPath[from] = false;
    }
}
//leetcode submit region end(Prohibit modification and deletion)

210. 课程表 II

相同问题:剑指 Offer II 113. 课程顺序

打印出可行的路径。

// DFS解法
class Solution {
    boolean[] onPath;
    boolean[] visited;
    LinkedList<Integer> trace;
    boolean hasCycle = false;

    public int[] findOrder(int numCourses, int[][] prerequisites) {
        onPath = new boolean[numCourses];
        visited = new boolean[numCourses];
        trace = new LinkedList<>();

        Map<Integer, List<Integer>> graph = new HashMap<>();

        for (int[] prerequisite : prerequisites) {
            //[0,1]表示,要想到达0必须先到达1,那么说明路径是这样的:1->0
            int from = prerequisite[1];
            int to = prerequisite[0];

            List<Integer> availables = graph.getOrDefault(from, new ArrayList<>());
            availables.add(to);
            graph.put(from, availables);
        }

        // 当前
        for (int i = 0; i < numCourses; i++) {
            traverse(graph, i);
        }
        if (hasCycle) {
            return new int[]{};
        }
        int[] res = new int[numCourses];
        Collections.reverse(trace);
        for (int i = 0; i < numCourses; i++) {
            res[i] = trace.get(i);
        }
        return res;
    }

    public void traverse(Map<Integer, List<Integer>> graph, int from) {
        // 如果路径上的节点已经被遍历过,那说明存在环
        if (onPath[from]) {
            hasCycle = true;
            return;
        }

        // 当前节点已经遍历过
        if (visited[from]) {
            return;
        }

        // visited就代表遍历过的节点,不需要再置为false
        visited[from] = true;
        onPath[from] = true;

        List<Integer> availables = graph.get(from);
        if (availables != null && availables.size() > 0) {
            for (int to : availables) {
                traverse(graph, to);
            }
        }
        onPath[from] = false;
        // 记录走过的路径
        trace.add(from);
    }
}

二分图判定

并查集

其他