Hard草稿★★★★★O(n) 時間 · O(1) 空間
GreedyArray
Patterns🪙 貪心
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

135CandyGreedyHardGreedy

n 個孩子站成一排,每人有一個評分 ratings[i]。你需要分配糖果,規則:每人至少 1 顆;相鄰兩人中評分較高的必須拿到更多糖果。回傳所需的最少糖果總數。

Example:

Input: ratings = [1,0,2] Output: 5 (分配 [2,1,2])

Intuition

TIP

兩次遍歷:先從左到右處理右邊比左邊大的情況,再從右到左處理左邊比右邊大的情況。

Approaches

1. Two Passes — O(n) / O(n)
  • Idea: 第一次從左到右確保右鄰比左鄰大時糖果更多,第二次從右到左確保左鄰比右鄰大時糖果更多。
  • Time: O(n)
  • Space: O(n)
class Solution {
    fun candy(ratings: IntArray): Int {
        val n = ratings.size
        val candies = IntArray(n) { 1 }

        // 從左到右
        for (i in 1 until n) {
            if (ratings[i] > ratings[i - 1]) {
                candies[i] = candies[i - 1] + 1
            }
        }

        // 從右到左
        for (i in n - 2 downTo 0) {
            if (ratings[i] > ratings[i + 1]) {
                candies[i] = maxOf(candies[i], candies[i + 1] + 1)
            }
        }

        return candies.sum()
    }
}
⭐ 2. Single Pass (slope counting) — O(n) / O(1)
  • Idea: 追蹤上升和下降斜坡的長度。上升時糖果遞增;下降時回頭補糖果。
  • Time: O(n)
  • Space: O(1)
class Solution {
    fun candy(ratings: IntArray): Int {
        val n = ratings.size
        if (n <= 1) return n

        var total = 1
        var up = 0
        var down = 0
        var peak = 0

        for (i in 1 until n) {
            when {
                ratings[i] > ratings[i - 1] -> {
                    up++
                    down = 0
                    peak = up
                    total += up + 1
                }
                ratings[i] < ratings[i - 1] -> {
                    down++
                    up = 0
                    // 如果下降長度超過峰值,峰值也需要加 1
                    total += down + if (down > peak) 1 else 0
                }
                else -> {
                    up = 0
                    down = 0
                    peak = 0
                    total += 1
                }
            }
        }
        return total
    }
}

🔑 Takeaways