赞
踩
n 个孩子站成一排。给你一个整数数组 ratings
表示每个孩子的评分。
你需要按照以下要求,给这些孩子分发糖果:
示例 1:
输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。
示例 2:
输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。
提示:
我们可以将「相邻的孩子中,评分高的孩子必须获得更多的糖果」这句话拆分为两个规则,分别处理。
我们遍历该数组两次,处理出每一个学生分别满足左规则或右规则时,最少需要被分得的糖果数量。每个人最终分得的糖果数量即为这两个数量的最大值。
具体地,以左规则为例:我们从左到右遍历该数组,假设当前遍历到位置 i i i,如果有 ratings [ i − 1 ] < ratings [ i ] \textit{ratings}[i - 1] < \textit{ratings}[i] ratings[i−1]<ratings[i] 那么 i i i 号学生的糖果数量将比 i - 1i−1 号孩子的糖果数量多,我们令 left [ i ] = left [ i − 1 ] + 1 \textit{left}[i] = \textit{left}[i - 1] + 1 left[i]=left[i−1]+1 即可,否则我们令 left [ i ] = 1 \textit{left}[i] = 1 left[i]=1。
在实际代码中,我们先计算出左规则 left \textit{left} left 数组,在计算右规则的时候只需要用单个变量记录当前位置的右规则,同时计算答案即可。
为什么取最大值是正确的思考:
我们取序列中的任意两点,A B
- 如果 A > B ,则按照左规则处理后,B不会比A多;按照右规则处理后,A一定比B多,那么A一定会被更新(变大),但L、R规则仍然成立:B不会比A多,A一定比B多;
- 同理可讨论 A<B;
- 当 A == B,A、B的值无论如何更新,都不影响 L、R规则
综上,取最大值后不影响某一规则的成立。
class Solution { public: int candy(vector<int>& ratings) { int kid, size = ratings.size(); vector<int> num(size, 1); kid = 1; while(kid < size){ if(ratings[kid-1] < ratings[kid]) num[kid] = num[kid-1] + 1; kid++; } kid = size-1; while(kid > 0){ if(ratings[kid-1] > ratings[kid]) num[kid-1] = max(num[kid-1], num[kid] + 1); kid--; } return accumulate(num.begin(), num.end(), 0); } };
时间复杂度:
O
(
n
)
O(n)
O(n),其中
n
n
n 是孩子的数量。我们需要遍历两次数组以分别计算满足左规则或右规则的最少糖果数量。
空间复杂度:
O
(
n
)
O(n)
O(n),其中
n
n
n 是孩子的数量。我们需要保存所有的左规则对应的糖果数量。
注意到糖果总是尽量少给,且从 1 1 1 开始累计,每次要么比相邻的同学多给一个,要么重新置为 1 1 1。依据此规则,我们可以画出下图:
其中相同颜色的柱状图的高度总恰好为
1
,
2
,
3
…
1,2,3 \dots
1,2,3…。
而高度也不一定一定是升序,也可能是
…
3
,
2
,
1
\dots 3,2,1
…3,2,1 的降序:
注意到在上图中,对于第三个同学,他既可以被认为是属于绿色的升序部分,也可以被认为是属于蓝色的降序部分。因为他同时比两边的同学评分更高。我们对序列稍作修改,下面是新序列——我们注意到右边的降序部分变长了(从3变为了4),使得第三个同学不得不被分配 4 4 4 个糖果。
依据前面总结的规律,我们可以提出本题的解法:我们从左到右枚举每一个同学,记前一个同学分得的糖果数量为 pre \textit{pre} pre:
这样,我们只要记录当前递减序列的长度 dec \textit{dec} dec,最近的递增序列的长度 inc \textit{inc} inc 和前一个同学分得的糖果数量 pre \textit{pre} pre 即可。
class Solution { public: int candy(vector<int>& ratings) { int n = ratings.size(); int ret = 1; int inc = 1, dec = 0, pre = 1; for (int i = 1; i < n; i++) { if (ratings[i] >= ratings[i - 1]) { dec = 0; pre = ratings[i] == ratings[i - 1] ? 1 : pre + 1; ret += pre; inc = pre; } else { dec++; if (dec == inc) { dec++; } ret += dec; pre = 1; } } return ret; } };
时间复杂度:
O
(
n
)
O(n)
O(n),其中
n
n
n 是孩子的数量。我们需要遍历两次数组以分别计算满足左规则或右规则的最少糖果数量。
空间复杂度:
O
(
1
)
O(1)
O(1),我们只需要常数的空间保存若干变量。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。