leetcode Candy

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     }
View Code

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     }
View Code

 

posted @ 2014-08-28 15:47  yanyichao  阅读(219)  评论(0编辑  收藏  举报