There are N children standing in a line. Each child is assigned a rating value.
You are giving candies to these children subjected to the following requirements:
Each child must have at least one candy.
Children with a higher rating get more candies than their neighbors.
What is the minimum candies you must give?
这题类似于trapping water题目。无论是填水还是发糖,影响因素都不只是一边,都是由左右两边的最大值最小值决定的。
1 如果孩子i+1的rate大于孩子i的rate,那么孩子i+1的糖果=孩子i的糖果+1,但是如果小于或者等于,并不能确定给孩子i+1多少颗糖。这时可以先不处理,然后逆序过来遍历一次,处理这些孩子。最后取出两者的最大值累加即可。空间复杂度O(n)
2 辅助数组的作用就是进行遍历时记录最大值和最小值。但是如果是非递减序列,就不需要辅助空间了,因为每个孩子给的糖果数就能确定下来
但是如果是递减序列,就不能唯一的确定了,如 1 5 4 3 ,第一个孩子给糖果数1,那第二个孩子给的糖果数是多少呢?是根据递减序列的长度决定的。5 4 3递减序列长度是3,那第二个孩子应该给3个糖果,第三个孩子应该给2个糖果,第四个孩子应该给4个糖果。那可以先对其不进行处理,递减序列的第一个已经给了糖果,先不管,4 3 ,长度为count:2,给的糖果总数为1+2=3,5对应的孩子现在的糖果数是pre:2,(count>=2)5对应的这个孩子的糖果应该重新分配,在总数上加(count-pre)+1
public class Candy {
//O(1)的空间复杂度
public int candy2(int[] ratings) {
if(ratings==null || ratings.length==0) {
return 0;
}
//前一个孩子给的糖果数
int pre = 1;
//递减序列的长度(不包含递减序列的第一个数)
int count = 0;
//总数sum
int sum = 1;
//从第二个孩子开始遍历
for(int i=1;i<ratings.length;i++) {
if(ratings[i]>=ratings[i-1]) {
if(count>0) {
sum += (1+count)*count/2;
if(count>=pre) { //对递减序列的第一个数进行重新修正
sum += count-pre+1;
}
//重置
count = 0;
pre=1;
}
pre = (ratings[i]==ratings[i-1]? 1:pre+1);
sum += pre;
} else {
count++;
}
}
//如果递减数列一直到结束
if(count>0) {
sum += (1+count)*count/2;
if(count>=pre) {
sum += count-pre+1;
}
}
return sum;
}
//两个数组 用一个数组也是ok的,反向遍历时,如果左边的rate比右边高,应该确保左边糖果数多。
public int candy(int[] ratings) {
if(ratings==null || ratings.length==0) {
return 0;
}
int[] lefts = new int[ratings.length];
int[] rights = new int[ratings.length];
//从左向右遍历
lefts[0]=1;
for(int i=1;i<ratings.length;i++) {
if(ratings[i]>ratings[i-1]) {
lefts[i] = lefts[i-1]+1;
} else {
lefts[i] = 1;
}
}
//从右向左遍历
rights[ratings.length-1] = 1;
for(int i=ratings.length-2;i>=0;i--) {
if(ratings[i]>ratings[i+1]) {
rights[i] = rights[i+1]+1;
} else {
rights[i] = 1;
}
}
int sum = 0;
for(int i=0;i<ratings.length;i++) {
sum += Math.max(lefts[i], rights[i]);
}
return sum;
}
}