leetcode 1443.Minimum Time to Collect All Apples in a Tree(收集苹果所需最短时间)

leetcode 1443.Minimum Time to Collect All Apples in a Tree(收集苹果所需最短时间)_第1张图片
给出节点个数n, edges是连接的边,[a,b]是连接的两个顶点。
hasApple表示第 i 个顶点上是否有苹果。

走一条边需要耗时1s, 从顶点0出发,最后回到顶点0,
问收集所有苹果所需最短的时间。

思路:

(1)DFS

可以把问题简化一下,
如果一个顶点,它的child有苹果,这个点必然会耗时2,因为要经过它进入child, 还要经过它返回顶点0.

如果一个顶点,它自己有苹果,那么也要耗时2,因为要走向它,还要返回上一级。

那么就可以DFS遍历,从叶子节点开始递归返回,child有苹果,+2,自己有苹果+2.
还要用一个visited记录每个节点是否已经被访问过。
例如图中的节点1,在进入4时它已经被访问过了,那么再进入5时它就不需要再+2。

出发点是0,所以节点0不需要+2.

该方法需要构建无向图。

class Solution {
    HashMap<Integer,List<Integer>> graph = new HashMap<>();
    HashSet<Integer> visited = new HashSet<>();

    public int minTime(int n, int[][] edges, List<Boolean> hasApple) {

        //make graph
        for(int[] edge : edges) {
            graph.putIfAbsent(edge[0], new LinkedList<>());
            graph.putIfAbsent(edge[1], new LinkedList<>());
            graph.get(edge[0]).add(edge[1]);
            graph.get(edge[1]).add(edge[0]);
        }

        return dfs(0, hasApple);
    }

    int dfs(int node, List<Boolean> hasApple) {
        visited.add(node);
        int res = 0;

        for(int child : graph.getOrDefault(node, new LinkedList<>())) {
            if(visited.contains(child)) continue;
            res += dfs(child, hasApple); 
        }

        if((res > 0 || hasApple.get(node)) && node > 0) res += 2;

        return res;
    }

(2)类似 Union-Find

前面已经说过,2种情况,

节点的child有苹果,时间+2,
节点自己有苹果,时间+2,
节点0除外,已访问过的节点除外。

刚刚的DFS是从上往下,但是是从下往上递归。

那是不是可以直接从下往上呢?

只需记录每个节点的parent, 然后从节点开始,不断访问它的parent,
节点自己有苹果,时间+2,同时它所有的parent的时间+2,
已访问过的和节点0除外。

    public int minTime(int n, int[][] edges, List<Boolean> hasApple) {

        int[] parent = new int[n];
        Arrays.fill(parent, -1);
        
        // Build tree like structure with each child pointing to its parent node
        // edge[0] is parent by default for edge[1]. 
        // If edge[1] is already assigned a parent, then make edge[1] a parent of edge[0]
        parent[0] = 0;
        for (int[] edge : edges) {
            if (parent[edge[1]] == -1) {
                parent[edge[1]] = edge[0];
            } else {
                parent[edge[0]] = edge[1];
            }
        }

        int timeSpent = 0;
        boolean[] visited = new boolean[n];
        visited[0] = true;

        for (int node = 1; node < n; ++node) {
            if (hasApple.get(node)) {
                for (int parentNode = node; !visited[parentNode]; parentNode = parent[parentNode]) {
                    visited[parentNode] = true;
                    timeSpent += 2;
                }
            }
        }

        return timeSpent;
    }

你可能感兴趣的:(leetcode,leetcode,深度优先,算法)