Description
給定一棵二元樹,如果從根到節點 X 的路徑上沒有任何節點的值大於 X,則稱 X 為「好節點」。回傳好節點的數量。
Example:
Input: root = [3,1,4,3,null,1,5] Output: 4 (好節點為 3, 3, 4, 5)
Intuition#
DFS 過程中傳遞「路徑上的最大值」,若當前節點值 >= 最大值,就是好節點。
- 從根往下遍歷時維護一個「到目前為止的最大值」
- 根節點一定是好節點(路徑上只有自己)
Approaches#
⭐ 1: Recursive DFS#
- 概念: DFS 傳遞路徑最大值,當前節點值 >= 最大值時計數 +1
- 時間複雜度:
O(n) - 空間複雜度:
O(h)
class Solution {
fun goodNodes(root: TreeNode?): Int {
return dfs(root, Int.MIN_VALUE)
}
private fun dfs(node: TreeNode?, maxSoFar: Int): Int {
if (node == null) return 0
val count = if (node.`val` >= maxSoFar) 1 else 0
val newMax = maxOf(maxSoFar, node.`val`)
return count + dfs(node.left, newMax) + dfs(node.right, newMax)
}
}2: Iterative DFS(Stack)#
- 概念: 使用堆疊模擬 DFS,每個元素同時記錄節點和路徑最大值
- 時間複雜度:
O(n) - 空間複雜度:
O(n)
class Solution {
fun goodNodes(root: TreeNode?): Int {
if (root == null) return 0
var count = 0
val stack = ArrayDeque<Pair<TreeNode, Int>>()
stack.addLast(root to Int.MIN_VALUE)
while (stack.isNotEmpty()) {
val (node, maxSoFar) = stack.removeLast()
if (node.`val` >= maxSoFar) count++
val newMax = maxOf(maxSoFar, node.`val`)
node.left?.let { stack.addLast(it to newMax) }
node.right?.let { stack.addLast(it to newMax) }
}
return count
}
}🔑 Takeaways#
- Pattern: DFS 中傳遞額外狀態(路徑最大值、路徑和等)
- 關鍵技巧: 將「路徑上的約束條件」轉化為遞迴參數,是處理路徑相關問題的通用技巧