1. 题目
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
评分更高的孩子必须比他两侧的邻位孩子获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
示例 1:
输入:[1,0,2]
输出:5
解释:你可以分别给这三个孩子分发 2、1、2 颗糖果。
示例 2:
输入:[1,2,2]
输出:4
解释:你可以分别给这三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这已满足上述两个条件。
Related Topics 贪心 数组
👍 573 👎 0
2. 题解
2.1 解法1: 两次遍历
根据题意, 可以定义 左规则和右规则,
- 左规则: 若
rating[i-1]<rating[i]
, 则多给一颗糖给 i - 右规则: 若
rating[i-1]>rating[i]
, 则多给一颗糖给 i-1
算法流程:
1.先从左至右遍历学生成绩 ratings,按照以下规则给糖,并记录在 left 中:
1.先给所有学生一颗糖
2.从左至右遍历过程中, 若 rating[i-1]<rating[i], 则多给 i 一个糖
经过此规则分配后,可以保证所有学生糖数量 满足左规则 。
2.同理,在此规则下从右至左遍历学生成绩并记录在 right 中,可以保证所有学生糖数量 满足右规则。
3.最终,取以上 2 轮遍历 left 和 right 对应学生糖果数的 最大值 ,这样则 同时满足左规则和右规则 ,即得到每个同学的最少糖果数量。
这样做的原因: 如果从左至右一趟遍历想要同时满足左右规则, 那么是不可能的, 因为 i-1 的小朋友的糖果数目会变化, 这样无法同时满足, 所以需要两趟遍历
代码:
class Solution {
public int candy(int[] ratings) {
int[] lefts = new int[ratings.length];
int[] rights = new int[ratings.length];
Arrays.fill(lefts, 1);
Arrays.fill(rights, 1);
// 从左至右遍历, 满足左规则
for (int i = 1; i < lefts.length; i++) {
if (ratings[i - 1] < ratings[i]) {
lefts[i] = lefts[i - 1] + 1;
}
}
// 从右往左遍历, 满足右规则
for (int i = rights.length - 1; i >= 1; i--) {
if (ratings[i - 1] > ratings[i]) {
rights[i - 1] = rights[i] + 1;
}
}
// 遍历两个数组, 每个元素取较大者
int ans = 0;
for (int i = 0; i < lefts.length; i++) {
ans += Math.max(lefts[i], rights[i]);
}
return ans;
}
}
优化:
1.不用预先填充数组, 可以在遍历过程中, 不符合左右规则的, 直接发一颗糖
2.在第二次从右往左遍历时, 可以同时计算结果
class Solution {
public int candy(int[] ratings) {
int[] lefts = new int[ratings.length];
int[] rights = new int[ratings.length];
// 最后一个访问的元素必须是 lefts[lefts.length-1]
for (int i = 0; i < lefts.length; i++) {
if (i > 0 && ratings[i - 1] < ratings[i]) {
lefts[i] = lefts[i - 1] + 1;
} else {
lefts[i] = 1;
}
}
int ans = 0;
// 最后一个访问的元素必须是 rights[0]
for (int i = rights.length - 1; i >= 0; i--) {
if (i < rights.length - 1 && ratings[i] > ratings[i + 1]) {
rights[i] = rights[i + 1] + 1;
} else {
rights[i] = 1;
}
// 这里直接累计结果
ans += Math.max(lefts[i], rights[i]);
}
return ans;
}
}
2.2 解法2: 一次遍历
讲解可参考: C++一次遍历!一次遍历!超级简单详细!
class Solution {
public int candy(int[] ratings) {
int ans = 1;
int inc = 1, dec = 0, last = 1;
for (int i = 1; i < ratings.length; ++i) {
if (ratings[i] >= ratings[i - 1]) {
last = ratings[i] == ratings[i - 1] ? 1 : last + 1;
ans += last;
inc = last;
dec = 0;
} else {
++dec;
if (dec == inc) ++dec;
ans += dec;
last = 1;
}
}
return ans;
}
}