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?

Solution:

最开始想到的是 从左往右循环,如果遇到 左边小于右边的, 右边的+1。 遇到左边大于右边的, 回退,直到右边大于左边,给每一个元素+1, 这样时间复杂度是O(n^2)。 得降:

接着就想到用stack,循环从左边开始,如果发现左边比右边大 则入stack,直到左边比右边小 ,然后出stack,给每个出stack的数加上其在stack里面的位置,即深度。

如果当前点比它前面的点大呢? candy[i] = candy[i - 1] + 1; 否则, candy[i] = 1;

这里新建了一个数组,rating, 它扩展了原数组,末尾加了一个-1, 用于对最后一个元素进行判断。

对于栈底元素,即临界元素,其值应该等于左边得到的值 和通过栈的到的值中间最大的那一个。

还要在循环外, 对stack进行一次操作。

对最后一个点 还得讨论,

1)如果最后一个点 比 前一个小 则不变
2)比前一个大 则为D(n -1) + 1
 
464 ms过大测试~~时间复杂度 O(n)。
 1 public class Solution {
 2     public int candy(int[] ratings) {
 3         // Note: The Solution object is instantiated only once and is reused by each test case.
 4         int l = ratings.length;
 5         int[] rating = new int[l + 1];
 6         for(int i = 0; i < l; i ++){
 7             rating[i] = ratings[i];
 8         }
 9         rating[l] = -1;
10         int sum = 0;
11         int d = 0;
12         int[] candy = new int[l];
13         Stack<Integer> st = new Stack<Integer>();
14         for(int i = 0; i < l; i ++){
15             if(i > 0 && rating[i] > rating[i - 1]){
16                 candy[i] = candy[i - 1] + 1;
17             }else{
18                 candy[i] = 1;
19             }
20             if(rating[i] > rating[i+1]){
21                 st.push(i);
22             }else{
23                 d = st.size();
24                 if(d > 0){
25                     for(int ii = 0; ii < d - 1; ii ++){
26                         int cur = st.pop();
27                         candy[cur] += ii+1;
28                     }
29                     int cur = st.pop();
30                     candy[cur] = ((d + 1) > candy[cur] ? (d + 1) : candy[cur]);// d+1 原因: 最小的那个元素没有入栈,栈的深度少了1.
31                 }
32             }
33             
34         }
35         d = st.size();
36         for(int ii = 0; ii < d - 1; ii ++){
37             int cur = st.pop();
38             candy[cur] += ii;
39         }
40         int cur = st.pop();
41         candy[cur] = (d > candy[cur] ? d : candy[cur]);
42         for(int i = 0; i < candy.length; i ++){
43             sum += candy[i];
44         }
45         return sum;
46     }
47 }

 其实,这一题可以想象成一个波, 它有上升和下降。 第一遍,考虑上升的所以情况; 第二遍,考虑下降的所以情况。 然后对于波峰,用两边的max 值当成它的值即可。

这样 思路变得更加清晰。 

 1 public class Solution {
 2     public int candy(int[] ratings) {
 3         // Note: The Solution object is instantiated only once and is reused
 4 //by each test case.
 5         int rLen = ratings.length;
 6         if (rLen == 0) return 0;
 7         int min = rLen; int give = 0;
 8         int[] gives = new int[rLen];
 9         for (int i = 1; i < rLen; i++) {
10             if (ratings[i] > ratings[i - 1]) give++;
11             else give = 0;
12             gives[i] = give;
13         }
14         give = 0;
15         for (int i = rLen - 2; i >= 0; i--) {
16             if (ratings[i] > ratings[i + 1]) give++;
17             else give = 0;
18             min += Math.max(give, gives[i]);
19         }
20         min += gives[rLen - 1];
21         return min;
22     }
23 }

 find out all local min rating, 
for each local min rating, start with 1 candy, and expand on both directions
until hit by local max.
return total candies.

O(n)

第二遍: 波的方法, 左边走一次右边走一次。

 1 public class Solution {
 2     public int candy(int[] ratings) {
 3         // Note: The Solution object is instantiated only once and is reused by each test case.
 4         if(ratings == null || ratings.length == 0) return 0;
 5         int len = ratings.length;
 6         int[] candy = new int[len];
 7         int sum = 0;
 8         for(int i = 0; i < len; i ++)
 9             candy[i] = 1;
10         for(int i = 1; i < len; i ++){
11             if(ratings[i - 1] < ratings[i]) candy[i] = candy[i - 1] + 1;
12         }
13         for(int i = len - 1; i > 0; i --){
14             if(ratings[i] < ratings[i - 1]) candy[i - 1] = Math.max(candy[i - 1], candy[i] + 1);
15         }
16         for(int i = 0; i < len; i ++)
17             sum += candy[i];
18         return sum;
19     }
20 }
原文地址:https://www.cnblogs.com/reynold-lei/p/3349915.html