老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
相邻的孩子中,评分高的孩子必须获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
示例 1:
输入: [1,0,2]
输出: 5
解释: 你可以分别给这三个孩子分发 2、1、2 颗糖果。
示例 2:
输入: [1,2,2]
输出: 4
解释: 你可以分别给这三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这已满足上述两个条件。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/candy
代码思路:
例如[4,3,2,1,1,0,2,3,2,2,1,2,0]
将序列分成三种情况
下降序列[4,3,2,1],[1,0],[3,2],[2,1],[2,0]
上升序列[0,2,3],[1,2]
平台序列[1,1],[2,2]
对于下降序列从最后面开始计算给糖果的数量,最右边肯定是1,然后依次上升。
对于上升序列,总最左边开始计算给糖果的数量,最左边肯定是1,然后依次上升。
对于平台序列应该全部赋值为1。
三种情况肯定会在左右端点的值上有重复,对于重复情况而言,肯定是有另一种情况对这个点的赋值需要比原来的值大,所以如果要赋的值比原来的值小,则不需要更改。
在如下情况下例子中的三种情况的赋值如下:
下降序列[4,3,2,1],[2,1],[2,1],[2,1],[2,1]
上升序列[1,2,3],[1,2]
平台序列[1,1],[1,1]
然后拼凑起来重复的地方取较大的值。
输入:[4,3,2,1,1,0,2,3,2,2,1,2,0]
输出:[4,3,2,1,2,1,2,3,1,2,1,2,1]
代码如下:
public int candy(int[] ratings) {
int i=0;
int n=0;
int front;
int count=1;
int length=ratings.length-1;
int[] candy=new int[length+1];
while(i<length) {
n=i;
if(n+1<=length&&ratings[n+1]<ratings[n]) {
//遇到了下降序列
while(n+1<=length&&ratings[n+1]<ratings[n]) {
n++;
}
//找到下降序列的头,front记录搜索到的下降的最右边的位置
front=n;
count=1;
while(n>=i) {
//从最右边开始赋值,如果比当前值小则不进行赋值
if(candy[n]<=count) {
candy[n]=count;
}
count++;
n--;
}
//将i变更到下降最右边的位置
i=front;
n=i;
}
if(n+1<=length&&ratings[n+1]==ratings[n]) {
//遇到了平台序列
while(n+1<=length&&ratings[n+1]==ratings[n]) {
n++;
}
//找到平台的最右边
front=n;
count=1;
while(n>=i) {
//对平台的所有元素赋值为1,并且需要原来的值比1小
if(candy[n]<=count) {
candy[n]=1;
}
n--;
}
i=front;
n=i;
}
if(n+1<=length&&ratings[n+1]>ratings[n]) {
//遇到了上升序列
while(n+1<=length&&ratings[n+1]>ratings[n]) {
n++;
}
//找到上升序列的最右边位置
front=n;
count=1;
while(i<=n) {
//从最左边的位置依次赋值
if(candy[i]<count) {
candy[i]=count;
}
count++;
i++;
}
i=front;
n=i;
}
}
count=0;
for(i=0;i<=length;i++) {
count=count+candy[i];
}
//算法的不足的补充,对于单一的元素,以上所有步骤都不做熟
if(length==1) {
return 1;
}else {
return count;
}
}
日常看结果:
代码分析:
在上述思路中需要对整个数组遍历三边,第一次是向前搜索下降、上升和平台的范围,第二次是对这个范围内的各个数进行赋值。最后一次是对整个数组的整体求和。所以时间复杂度是O(N)。
空间复杂度上,需要一个和ratings相同大小的candy数组,所以空间复杂都市O(N)。
博主感觉可以更简单一点,思路正在思考,博主也是新手,有什么不对,代码不太简便还行见谅。