原题:https://oj.leetcode.com/problems/candy/
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?
此题解题过程中个人认为最关键的有两点:
1)正确理解题意!
注意题目中的表达:有更高rating的child要比他们的 “邻居” 有更多的糖果。有两点很容易误解需要注意:
a)如果两个孩子是邻居,那么有更高rating的孩子必须有更多的糖果,如果两个孩子不是相邻,他们糖果数目相对多少跟自己的rating没有必然联系!
b)对于相邻的孩子,其ratings相等的情况并没有要求,如果两个相邻的孩子rating相等,他们的糖果数目可以不相等。
2)在正确理解了题意的基础上,给每个孩子计算出他应该得多少块糖。方法如下:
对于任意一个孩子,他的糖果数需要考虑两点:
a)他的rating跟前面孩子rating的关系---如果rating比前面的孩子高,那么他得到的糖数至少为前面孩子糖果数+1(后续代码中的candyArr[i-1] + 1),如果其rating小于等于(注意包括等于)前面孩子的rating,则无需考虑前面孩子糖果数的关系。
b)他的rating跟后面孩子rating的关系(注意不能只考虑他的邻居)----这个是难点,解决方法是:查看他后面rating值严格单调递减的孩子数目。
举例:ratings: 5,4,3,2,2,x........
对于rating=5这个孩子来说,他后面严格单调递减的孩子有三个,分别是:4,3,2。接下去的连续的2已经不需要考虑,理由如a)中所述,也就是后面的2这个孩子的糖果数已经跟前面无关系,不受前面限制了。这样,我们需要给rating=5这个孩子留出3的可减空间,以便他后面孩子糖果数至少为1。 也就是说,考虑这个孩子跟后面孩子ratings的关系,他至少应该有1+3=4块糖。
最后,同时满足a)和b)条件的数字,就是当前这个孩子应该分发的糖果数。
AC代码:
public class Candy {
public int candy(int[] ratings) {
if(ratings == null || ratings.length == 0) return 0;
int length = ratings.length;
int[] minSpaceForFollows = new int[length]; //用一个数组来记录每个孩子需要给他后面孩子留出的可减空间
for(int i=0;i<length;i++) {
int space = 0;
for(int j=i+1;j<length;j++) {
if(ratings[j] >= ratings[j-1]) {
break;
} else {
space++;
}
}
minSpaceForFollows[i] = space;
}
int result = 0;
int[] candyArr = new int[length];
candyArr[0] = (minSpaceForFollows[0] + 1);
result += candyArr[0];
for(int i=1;i<minSpaceForFollows.length;i++) {
int leftFactor = 1;
if(ratings[i] > ratings[i-1]) { //这个孩子糖果数考虑他前面孩子所需的最小值
leftFactor = candyArr[i-1] + 1;
}
int rightFactor = 1 + minSpaceForFollows[i]; //这个孩子考虑他后面孩子所需的最小值
candyArr[i] = Math.max(leftFactor, rightFactor);
result += candyArr[i];
}
return result;
}
}