leetcode-通知所有员工所需的时间

 题目是LeetCode第179场周赛的第三题,链接:通知所有员工所需的时间。问题较长就不搬运了,详见原题描述。

 其实这可以看做是求一棵树从根节点到叶子节点的最大加权路径和,通知时间就是权重。所以一种比较简单的思路就是直接深度优先遍历整棵树,同时记录最大加权路径和。具体做法用递归实现,为了求得根节点到叶子节点的最大加权路径和,等价于求根节点到其子节点的加权路径(这道题里是到各个子节点的加权路径一样大的)+其子节点到叶子节点的最大加权路径和,这就是需要的递归公式。

 这么做的时间复杂度和空间复杂度都是 O ( N ) O(N) O(N)

 JAVA版代码如下:

class Solution {
    private Map> manager2sub;

    private int maxMins(int id, int[] informTime) {
        if (informTime[id] > 0) {
            List subs = manager2sub.get(id);
            int maxTime = 0;
            for (int i : subs) {
                int subTime = maxMins(i, informTime);
                if (subTime > maxTime) {
                    maxTime = subTime;
                }
            }
            return informTime[id] + maxTime;
        }
        else {
            return 0;
        }
    }
    
    public int numOfMinutes(int n, int headID, int[] manager, int[] informTime) {
        manager2sub = new HashMap<>();
        for (int i = 0; i < n; ++i) {
            List tmp = manager2sub.containsKey(manager[i]) ? manager2sub.get(manager[i]) : new LinkedList<>();
            tmp.add(i);
            manager2sub.put(manager[i], tmp);
        }
        return maxMins(headID, informTime);
    }
}

 提交结果如下:


 从leetcode的评论区发现了另一个更巧妙的方法,就是从底往顶的方式(上面的DFS实际上是从顶到底),通过计算叶子节点到根节点的时间,可以不用建树(直接利用输入的manager和informTime即可),但是原代码没有优化,所以会比较慢。在原代码的基础上,考虑到在往上走的过程中,会有很多节点被重复访问,所以用了一个额外的数组记录每个节点到根节点的时间,从而避免重复计算,大大加快了速度。同样的时间复杂度和空间复杂度均为 O ( N ) O(N) O(N)

 JAVA版代码如下:

class Solution {
    private int[] toRootMins;

    private int timeToRoot(int headID, int id, int[] manager, int[] informTime) {
        if (id == headID) {
            return 0;
        }
        if (toRootMins[id] != 0) {
            return toRootMins[id];
        }
        if (toRootMins[manager[id]] != 0) {
            toRootMins[id] = toRootMins[manager[id]] + informTime[manager[id]];
            return toRootMins[id];
        }
        else {
            toRootMins[id] = timeToRoot(headID, manager[id], manager, informTime) + informTime[manager[id]];
            return toRootMins[id];
        }
    }
    
    public int numOfMinutes(int n, int headID, int[] manager, int[] informTime) {
        int maxMins = 0;
        toRootMins = new int[n];
        for (int i = 0; i < informTime.length; ++i) {
            if (informTime[i] == 0) {
                int totalMins = timeToRoot(headID, i, manager, informTime);
                if (totalMins > maxMins) {
                    maxMins = totalMins;
                }
            }
        }
        return maxMins;
    }
}

 提交结果如下:


 Python版代码如下:

class Solution:
    def numOfMinutes(self, n: int, headID: int, manager: List[int], informTime: List[int]) -> int:
        toRootMins = [0 for _ in range(n)]
        def timeToRoot(id):
            if id == headID:            #总负责人
                return 0
            if toRootMins[id] != 0:     #已知当前员工节点到总负责人节点时间,直接返回
                return toRootMins[id]
            #已知当前员工节点的上司节点到总负责人节点时间,那就在这基础上加上上司节点到当前员工节点的时间,否则需要递归计算
            toRootMins[id] = (toRootMins[manager[id]] + informTime[manager[id]]) if toRootMins[manager[id]] != 0 else (timeToRoot(manager[id]) + informTime[manager[id]])
            return toRootMins[id]
        maxMins = 0
        for i in range(n):
            if informTime[i] == 0:      #只需要考虑叶子节点也即最下层员工节点
                tmp = timeToRoot(i)
                if tmp > maxMins:
                    maxMins = tmp
        return maxMins

 提交结果如下:


你可能感兴趣的:(LeetCode,算法,leetcode,java,数据结构,python)