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进行一次操作。
对最后一个点 还得讨论,
2)比前一个大 则为D(n -1) + 1
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 }