分糖果
n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。
你需要按照以下要求,给这些孩子分发糖果:
- 每个孩子至少分配到
1个糖果。 - 相邻两个孩子中,评分更高的那个会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。
示例 1:
输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。
示例 2:
输入:**ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。
提示:
n == ratings.length1 <= n <= 2 * 10^40 <= ratings[i] <= 2 * 10^4
标准的解法是前后两次遍历取最大,但这样会消耗的空间,这里给出一次遍历贪心算法的实现.
思路:
首先只考虑ratings不减的情况:若ratings[i]等于ratings[i-1],此时糖果数可直接从重新开始;若ratings[i]ratings[i-1],只需分发比上一位多一个糖果即可。这部分我们只需要一个变量pre维护上一位的糖果数
1 | int candy = 1, pre = 1; |
接下来考虑ratings的递减部分:例如ratings[i-1] = 3,ratings[1] = 2,当pre = 3时,我们只考虑现有的,增加第个小朋友时,最优解即是只给他一个糖果。接下来,若下一位ratings仍递减,那么我们也只给新的小朋友一个糖果,不过,我们还需要为前一个小朋友再增加一个糖果。但是,如果下一位仍是递减,我们就需要增加个糖果了,因为最开始的个糖果的小朋友和他右边评分更低的小朋友糖果数一样,我们需要再为他分配一个糖果。
我们需要一个变量peak记录递减序列的头,即第一个小朋友的糖果数,对于剩下的小朋友,我们只需倒着发放,最后一位一个,倒数第二位两个,,直到第二个小朋友,然后再修正第一个小朋友的糖果数,使其高于第二个小朋友。
我们从遍历的角度去实现:再用一个变量de记录递减序列的长度,当新增的ratings小于前一位,我们总共需要额外de个糖果(递减序列除第一个外+新的小朋友 每人一个)。特别地,当depeak时,第二位的糖果数将追上第一位,这时我们每次需要de+1个糖果(补偿)
及时更新de,在递减序列结束时重置de,同时更新pre(必为)。这里,我们可以省去peak变量,直接用pre来代替,在递减序列中不再更新pre,让它充当peak,而在出递减序列后再重新将其重置为。
1 | int candy(vector<int>& ratings) { |
时间复杂度:,空间复杂度:.
