20.12.24 135. 分发糖果

题目

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

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

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

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

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

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

思路

  1. 为数不多能做出来的困难题,虽然思路不是很清晰
  2. 数组count是用来记录递增时的各个孩子的糖果数,递减时不使用count记录,所以递减部分的count都等于1
  3. countDecline是记录分给递减时孩子的糖果数
  4. declineBeginIndex是递减开始的索引,需要在合适的时候(遇到递增或相同时)变回-1,-1的意义就是还没确定当前递减开始的索引
  5. 递增部分就是改变count和更新declineBeginIndex,相同部分就是更新declineBeginIndex
  6. 递减部分,如果declineBeginIndex等于-1就更新它,随后更新countDecline,因为前面都是最优的,如果出现新的递减,末尾两个糖果数必定是等于1,所以要将前面所有递减部分都+1
  7. 最重要的部分是,举个例子
    • 1,2,5,3,2,1。rating=5的地方,count=3,当遍历到最后的rating=1的地方时,会更新ranting=3的地方count=3,那么就要把rating=5的count+1
    • 1,2,5,3,2。而这里,递减时rating=5的count不用更新
  8. 看了题解,思路是类似的,不过别人会更清晰,代码也更容易理解。两次遍历,第一次从左往右,用left数组记录递增部分(其实就是我的count);第二次从右往左,用一个变量right记录递减部分,然后取right和left对应值较大的作为最终结果的一部分(解决了我的第7点)

代码

class Solution {
public:
    int candy(vector<int>& ratings) {
        vector<int> count(ratings.size(), 1);
        int countDecline = 0, declineBeginIndex = -1;
        for(int i = 1; i < ratings.size(); ++i){
            if(ratings[i] > ratings[i-1]){
                count[i] = count[i-1] + 1;
                declineBeginIndex = -1;
            }
            else if(ratings[i] < ratings[i-1]){
                if(declineBeginIndex == -1) declineBeginIndex = i;
                if(ratings[declineBeginIndex] < ratings[declineBeginIndex-1]
                    && 1 + i - declineBeginIndex == count[declineBeginIndex-1]) ++count[declineBeginIndex-1];
                countDecline += i - declineBeginIndex;
            }
            else declineBeginIndex = -1;
        }
        
        int ans = 0;
        for(auto c:count) ans += c;
        return ans + countDecline;
    }
};
posted @ 2020-12-24 09:55  肥斯大只仔  阅读(48)  评论(0编辑  收藏  举报