Description

一家公司有 n 位員工,每位員工有一位直屬主管(除了總經理)。給定總經理 headID、每位員工的主管 manager[],以及每位主管通知直屬下屬所需時間 informTime[]。回傳通知所有員工所需的總時間。

Example:

Input: n = 6, headID = 2, manager = [2,2,-1,2,2,2], informTime = [0,0,1,0,0,0] Output: 1

Intuition#

本質是一棵多叉樹,求從根到所有葉節點的最長路徑。

  • 組織架構就是一棵以 headID 為根的多叉樹
  • 通知是從上而下傳播的,每個主管同時通知所有下屬
  • 總時間就是根到所有葉節點路徑中,時間總和最大的那條

Approaches#

1: 建圖 + DFS#

  • 概念: 先用鄰接表建圖,再從根 DFS,求最長路徑的通知時間
  • 時間複雜度: O(n)
  • 空間複雜度: O(n)
class Solution {
    fun numOfMinutes(n: Int, headID: Int, manager: IntArray, informTime: IntArray): Int {
        val children = Array(n) { mutableListOf<Int>() }
        for (i in 0 until n) {
            if (manager[i] != -1) {
                children[manager[i]].add(i)
            }
        }
        return dfs(headID, children, informTime)
    }

    private fun dfs(node: Int, children: Array<MutableList<Int>>, informTime: IntArray): Int {
        var maxTime = 0
        for (child in children[node]) {
            maxTime = maxOf(maxTime, dfs(child, children, informTime))
        }
        return informTime[node] + maxTime
    }
}

⭐ 2: 自底向上(不建圖)#

  • 概念: 對每個葉節點,沿著 manager 陣列往上累加時間到根,用快取避免重複計算
  • 時間複雜度: O(n)
  • 空間複雜度: O(n)
class Solution {
    fun numOfMinutes(n: Int, headID: Int, manager: IntArray, informTime: IntArray): Int {
        val memo = IntArray(n) { -1 }
        memo[headID] = 0
        var result = 0
        for (i in 0 until n) {
            result = maxOf(result, dfs(i, manager, informTime, memo))
        }
        return result
    }

    private fun dfs(i: Int, manager: IntArray, informTime: IntArray, memo: IntArray): Int {
        if (memo[i] != -1) return memo[i]
        memo[i] = informTime[manager[i]] + dfs(manager[i], manager, informTime, memo)
        return memo[i]
    }
}

🔑 Takeaways#

  • Pattern: 多叉樹求根到葉的最長路徑,DFS 自然適合
  • 關鍵技巧: 自底向上方法可以省去建圖步驟,用 memoization 確保每個節點只計算一次