贪心算法
Posted 浮云神码
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了贪心算法相关的知识,希望对你有一定的参考价值。
今天分享LeetCode第135题,分糖果。题目如下:
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
评分更高的孩子必须比他两侧的邻位孩子获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
根据题意:评分更高的孩子必须比他两侧邻位的孩子分的糖果更多,多几个呢?至少多一个。
假设评分为一个递增序列,第一个孩子分1颗糖果, 第二个孩子分2颗糖果,... 第N个孩子分N颗糖果,我们很容易就计算出糖果的总数。
假设评分为一个递减序列,该怎么分配呢?假设还是上面的分配方式,第一个孩子分1颗糖果,第二个孩子要比第一个孩子分的少,最少也要分1颗,这就产生了矛盾,我们需要调整分给第一个孩子的糖果,分给第一个小朋友2颗,第二个小朋友1颗。那么第三个小朋友呢?我们又需要再调整前两个小朋友分的糖果。好麻烦... 反向思考一下:从最后一个孩子开始分糖果。第N个小朋友分1个,第N-1个小朋友分2个, 第i个小朋友分N+1-i个,第1个小朋友分N个。这正是按递增序列进行分配的结果。
在评分记录中,一会是递增序列,一会是递减序列,对于这两种情况,我们从左向右处理递增序列,从右向左处理递减序列,最终取两者之间的较大值作为结果,满足评分更高的孩子必须比他两侧邻位的孩子分的糖果更多
/**
* https://leetcode-cn.com/problems/candy
* 135. 分发糖果
* 难度 困难
* 老师想给孩子们分发糖果,有 N个孩子站成了一条直线,
* 老师会根据每个孩子的表现,预先给他们评分。
* <p>
* 你需要按照以下要求,帮助老师给这些孩子分发糖果:
* <p>
* 每个孩子至少分配到 1 个糖果。
* 评分更高的孩子必须比他两侧的邻位孩子获得更多的糖果。
* 那么这样下来,老师至少需要准备多少颗糖果呢?
* <p>
* 示例1:
* 输入:[1,0,2]
* 输出:5
* 解释:你可以分别给这三个孩子分发 2、1、2 颗糖果。
* <p>
* 示例2:
* 输入:[1,2,2]
* 输出:4
* 解释:你可以分别给这三个孩子分发 1、2、1 颗糖果。
* 第三个孩子只得到 1 颗糖果,这已满足上述两个条件。
* <p>
* 来源:力扣(LeetCode)
* 链接:https://leetcode-cn.com/problems/candy
*/
public class Candy {
public int candy(int[] ratings) {
int sum = 0;
int n = ratings.length;
// 基于贪心原则, 每个小朋友只分一个糖果
int[] candies = new int[n];
// 基于贪心算法, 毫无疑问, 第一个小朋友分一个就够了
candies[0] = 1;
// 从前向后遍历, 只对当前评分大于前一个评分的情况进行处理
// 满足条件: 当我比左边小朋友评分高的话, 我的糖果比他多1个
// rating[i + 1] = rating[i] + 1;
for (int i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
candies[i] = candies[i - 1] + 1;
} else {
// 否则, 只分一个糖果
candies[i] = 1;
}
}
// 从后向前遍历, 只对当前评分大于后一个评分的情况进行处理
// 满足条件: 当我比右边小朋友评分高的话, 我的糖果比他多1个
// rating[i] = rating[i + 1] + 1;
int[] candies2 = new int[n];
candies2[n - 1] = 1;
for (int i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
candies2[i] = candies2[i + 1] + 1;
} else {
candies2[i] = 1;
}
}
// 对于第i个小朋友, 同时满足条件的话, 取两者中的最大值即可
for (int i = 0; i < n; i++) {
sum += Math.max(candies[i], candies2[i]);
}
return sum;
}
}
以上是关于贪心算法的主要内容,如果未能解决你的问题,请参考以下文章