1 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 先求出相邻小孩的优先级。
2 积分得到每个小孩的糖果数。再加上最小小孩糖果数等于1的限制条件。
3 积分得到总的糖果数。
代码如下:
1 /* 2 * 优先级相同时,糖果数相同 3 */ 4 private int sign(int i) { 5 if (i > 0) { return 1; } 6 if (i < 0) { return -1; } 7 return 0; 8 } 9 10 private int[] candyDelta(int[] ratings) { 11 // delta保存与上一个小孩的优先级 12 int[] delta = new int[ratings.length]; 13 delta[0] = 0; 14 for (int i = 1; i < ratings.length; i++) { 15 delta[i] = sign(ratings[i] - ratings[i-1]); 16 } 17 return delta; 18 } 19 20 private int calCandies(int[] delta) { 21 // 计算第一个小孩糖果数为0时,每一个小孩的糖果数。这里糖果数可能为负。 22 int[] candies = new int[delta.length]; 23 candies[0] = 0; 24 for (int i = 1; i < candies.length; i++) { 25 candies[i] = candies[i-1] + delta[i]; 26 } 27 28 // 找到糖果数最小的小孩 29 int min = Integer.MAX_VALUE; 30 for (int i = 0; i < candies.length; i++) { 31 if (min > candies[i]) { 32 min = candies[i]; 33 } 34 } 35 36 // 糖果数最小的小孩给1个糖果,并据此分配糖果给其他小絯 37 for (int i = 0; i < candies.length; i++) { 38 candies[i] = candies[i] - min + 1; 39 } 40 // 计算糖果数 41 Integer total = 0; 42 for (int candy : candies) { 43 total += candy; 44 } 45 return total; 46 } 47 48 public int candy(int[] ratings) { 49 if (ratings.length == 1) { 50 return 1; 51 } 52 53 int[] delta = candyDelta(ratings); 54 55 int total = calCandies(delta); 56 57 return total; 58 }
2 Candy
代码1放到leetcode中,通不过{1,2,2}这个测试用例,返回5,而leetcode结果是4。其原因在于题设中并没有限定两个相邻的rating相同的小孩的糖果数相等。
可以在有相邻小孩rating相同处截断,然后分别计算两部分的candies。
更进一步的,可以从左往右计算,在左边小孩权重不小于右边小孩处截断;然后从右往左计算,在右边小孩权重不小于左边小孩处截断。
即从左往右报数时,第一次的计算结果是满足条件的;从右往左报数时,第二次的计算结果是满足条件的。最后将两次的计算结果合并,即为最终解。
代码如下:
1 private void calCandies(int[] candies, int[] ratings) { 2 candies[0] = 1; 3 if (ratings.length == 1) { return; } 4 5 // 从左往右 6 int[] candiesLeft = new int[ratings.length]; 7 candiesLeft[0] = 1; 8 for (int i = 1; i < ratings.length; i++) { 9 if (ratings[i] > ratings[i-1]) { 10 candiesLeft[i] = candiesLeft[i-1] + 1; 11 }else { 12 candiesLeft[i] = 1; 13 } 14 } 15 16 // 从右往左 17 int[] candiesRight = new int[ratings.length]; 18 candiesRight[ratings.length-1] = 1; 19 for (int i = ratings.length-2; i >= 0; i--) { 20 if (ratings[i] > ratings[i+1]) { 21 candiesRight[i] = candiesRight[i+1] + 1; 22 }else { 23 candiesRight[i] = 1; 24 } 25 } 26 27 // 合并 28 for (int i = 0; i < candies.length; i++) { 29 candies[i] = Math.max(candiesLeft[i], candiesRight[i]); 30 } 31 } 32 33 34 public int candy(int[] ratings) { 35 if (ratings.length == 1) { 36 return 1; 37 } 38 39 int[] candies = new int[ratings.length]; 40 calCandies(candies, ratings); 41 42 // 计算糖果数 43 Integer total = 0; 44 for (int candy : candies) { 45 total += candy; 46 47 } 48 return total; 49 }