【LeetCode】135. 分发糖果

leetcode

 

解题思路

该问题要求根据孩子的评分分配糖果,满足相邻高分孩子获得更多糖果且总数最少。核心思路是 ​​两次遍历贪心算法​​:

  1. ​​从左到右遍历​​:确保每个孩子比左边评分高的孩子多一颗糖果。
  2. ​​从右到左遍历​​:确保每个孩子比右边评分高的孩子多一颗糖果,同时避免覆盖左侧遍历的结果,取两次遍历中的最大值。

关键步骤

  1. ​​初始化数组​​:每个孩子至少1颗糖果。
  2. ​​左→右遍历​​:若当前孩子评分高于左边,则糖果数比左边多1。
  3. ​​右→左遍历​​:若当前孩子评分高于右边,则糖果数比右边多1(但需与当前值取最大值)。
  4. ​​累加总数​​:最终每个孩子的糖果数是左右遍历结果的最大值。

代码实现

func candy(ratings []int) int {
    n := len(ratings)
    if n == 0 {
        return 0
    }

    // 初始化每个孩子至少1颗糖果
    candies := make([]int, n)
    for i := range candies {
        candies[i] = 1
    }

    // 从左到右遍历,处理右侧比左侧高的情况
    for i := 1; i < n; i++ {
        if ratings[i] > ratings[i-1] {
            candies[i] = candies[i-1] + 1
        }
    }

    // 从右到左遍历,处理左侧比右侧高的情况,并取最大值
    for i := n-2; i >= 0; i-- {
        if ratings[i] > ratings[i+1] {
            // 避免覆盖左→右的结果,取左右遍历中的最大值
            candies[i] = max(candies[i], candies[i+1]+1)
        }
    }

    // 累加总糖果数
    total := 0
    for _, c := range candies {
        total += c
    }
    return total
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

代码注释

  1. ​​初始化数组​​:candies数组初始化为全1,满足每个孩子至少1颗糖果的条件。
  2. ​​左→右遍历​​:若当前孩子评分高于左侧,则糖果数设为左侧糖果数+1(如示例1中第三个孩子初始为1,左→右遍历后变为2)。
  3. ​​右→左遍历​​:若当前孩子评分高于右侧,则比较当前糖果数与右侧糖果数+1的较大值(如示例1中第一个孩子初始为1,右→左遍历后变为2)。
  4. ​​避免覆盖​​:右→左遍历时取max(candies[i], candies[i+1]+1),保证左→右的结果不被破坏。

测试示例

func main() {
    fmt.Println(candy([]int{1, 0, 2}))  // 输出: 5
    fmt.Println(candy([]int{1, 2, 2})) // 输出: 4
}

复杂度分析

  • ​​时间复杂度​​:O(n),两次独立遍历数组。
  • ​​空间复杂度​​:O(n),存储糖果数的数组。

关键点

  • ​​贪心策略​​:通过两次单向遍历分别处理左右相邻关系,确保局部最优推导全局最优。
  • ​​边界处理​​:评分相同的情况(如示例2中的第二个和第三个孩子)不需要额外增加糖果。
  • ​​动态比较​​:右→左遍历时取最大值,保证同时满足左右条件。
posted @ 2025-04-25 10:56  云隙之间  阅读(23)  评论(0)    收藏  举报