一、题目
有N个孩子站成一排,每个孩子有一个分值。现在你需要为这些孩子分配糖果,但需要满足下面的需求:
- 每个孩子至少分一个。
- 拥有较高分值的孩子得到的糖果要比与他相邻的孩子得到的数量多
那么最少
需要给这些孩子分配多少糖果?
二、分析
1、如果孩子当前的分值大于
前一个孩子,当前孩子分得糖果数量应该是 前一个孩子分得糖果数加1
。
下图中curr代表当前孩子,图中上半部分对应每个孩子的分值
,下半部分对应每个孩子分配的糖果数
.
后文中此类图形同理。
2、如果当前孩子的分值等于
前一个孩子的分值,则当前孩子所分得糖果数量应该是1
。(注意题干是:分配最少糖果)
3、如果连续下降
的,如果当前孩子的分值小于
前一个孩子的分值,我们还不能得出当前位置的糖果数是多少(不知道有多少连续下降数),继续看下面
孩子所具有的分值连续下降时,那么我们使用countDown
来存放连续下降数。下图中,在curr位置处countDown = 2。(3-2,2-1)
如果在下降序列中,当前值等于前一个人的值或大于前一个人的值,那么不在构成下降序列,那么我们将通过数列求和公式
来计算这段连续下降序列的长度。下图为等差数列求和公式。
当计算下降区间长度时,需要考虑pre变量
。下图中pre为2,因此接下来的两次糖果分配数量,无法按依次递减的方式分配,因为这样,因此第2次分配的数量将会是0,而每个孩子最少要分配一个。
在这种情况下,countDown >= prew,这样我们需要修改pre位置处为孩子分配的糖果数,pre = countdown – pre + 1。修正后可以保证每个孩子至少分配一个。
三、代码实现
public static int candy(int[] ratings) {
/**
* pre:前面元素能够得到的糖数
* countDown:连续下降数
* total:最少分配的糖果数
*/
int pre = 1, countDown = 0, total = 1;
for (int i = 1; i < ratings.length; i++) {
if (ratings[i] >= ratings[i - 1]) { //当前元素大于等于前一元素
if (countDown > 0) {
total += countDown * (countDown + 1) / 2;
if (countDown >= pre) {
total += countDown - pre + 1;
}
pre = 1;
countDown = 0;
}
//如果当前元素等于前一元素,则当前元素为1,否则,当前元素+1
pre = ratings[i] == ratings[i - 1] ? 1 : pre + 1;
total += pre;
} else { //当前元素小于前一元素
countDown++;
}
}
if (countDown > 0) {
total += countDown * (countDown + 1) / 2;
if (countDown >= pre) {
total += countDown - pre + 1;
}
}
return total;
}
四、鸣谢
文章1:http://www.allenlipeng47.com/blog/index.php/2016/07/21/candy/
文章2:https://blog.csdn.net/revivedsun/article/details/52897147