发糖果

力扣题目链接(opens new window)

老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。

你需要按照以下要求,帮助老师给这些孩子分发糖果:

  • 每个孩子至少分配到 1 个糖果。
  • 相邻的孩子中,评分高的孩子必须获得更多的糖果。

那么这样下来,老师至少需要准备多少颗糖果呢?

示例 1:

  • 输入: [1,0,2]
  • 输出: 5
  • 解释: 你可以分别给这三个孩子分发 2、1、2 颗糖果。

示例 2:

  • 输入: [1,2,2]
  • 输出: 4
  • 解释: 你可以分别给这三个孩子分发 1、2、1 颗糖果。第三个孩子只得到 1 颗糖果,这已满足上述两个条件。

思路

根据示例1、2来看,我们只需要对满足规则的两种情况发放糖果即可,目标是在满足规则的前提下消耗最少的糖果(因此发的糖果数量有可能是不公平的)

怎么做呢?其实也简单,就是遍历数组,比较前后元素的大小关系,由此分配糖果即可

但是细想一下,遍历过程也是有坑的

举个例子:

从左往右遍历ratings数组,得到每个小孩应该分配的糖果数【左边孩子与右边孩子相比得出的结果】

此时的贪心:

局部最优:只要右边评分比左边大(ratings[i] > ratings[i - 1]),右边的孩子就多一个糖果

全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果

//从左往右遍历ratings数组,左边孩子与右边孩子相比
for(int i = 1; i < ratings.size(); ++i){//从下标1开始
    if((ratings[i] > ratings[i - 1]) candyCount[i] = candyCount[i - 1] + 1;
}

但是,下标4和5位置,下标5的评分比4低,但是获得的糖果数一样,这不满足规则

所以还要从右往左遍历一遍【右边孩子与左边孩子相比得出的结果】,综合之后取最大值得出要分配的糖果数

此时的贪心:

局部最优:只要左边评分比右边大(ratings[i] > ratings[i + 1]),左边的孩子就多一个糖果

全局最优:相邻的孩子中,评分高的左孩子获得比右边孩子更多的糖果

//从右往左遍历ratings数组,右边孩子与左边孩子相比
for(int i = ratings.size() - 2; i >= 0; --i){//从倒数第二个下标开始
    if(ratings[i] > ratings[i + 1]){
        candyCount[i] = max(candyCount[i + 1] + 1, candyCount[i]);//取当前糖果数与之前的最大值
    }        
}

注意:将右边孩子和左边孩子相比时,必须从右往左遍历,不能从左往右然后通过改下标的方式来比较

代码

本题仍然采用了两次贪心策略

  • 一次是从左到右遍历,只比较右边孩子评分比左边大的情况。
  • 一次是从右到左遍历,只比较左边孩子评分比右边大的情况。

两次贪心最终可以得到满足规则的糖果分配数

步骤如下:

1、创建糖果数统计数组

2、从左往右遍历ratings数组,左边孩子与右边孩子相比

3、从右往左遍历ratings数组,右边孩子与左边孩子相比

4、统计糖果数

class Solution {
public:
    int candy(vector<int>& ratings) {
        //定义糖果统计数组
        vector<int> candyCount(ratings.size(), 1);//默认给一个糖
        //从左往右遍历ratings数组,左边孩子与右边孩子相比
        for(int i = 1; i < ratings.size(); ++i){//从下标1开始
            if(ratings[i] > ratings[i - 1]) candyCount[i] = candyCount[i - 1] + 1;
        }

        //从右往左遍历ratings数组,右边孩子与左边孩子相比
        for(int i = ratings.size() - 2; i >= 0; --i){//从倒数第二个下标开始
            if(ratings[i] > ratings[i + 1]){
                candyCount[i] = max(candyCount[i + 1] + 1, candyCount[i]);
            }
        }
        //统计糖果数
        int res = 0;
        for(int c : candyCount) res += c;
        return res;
    }
};