题目:
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?
代码:
class Solution { public: int candy(vector<int>& ratings) { const size_t len = ratings.size(); std::vector<int> candyNum(len); // from left to right for (size_t i = 1; i < len; ++i){ if (ratings[i] > ratings[i-1]) candyNum[i] = candyNum[i-1] + 1; } // from right to left for (size_t i = 1; i < len; ++i){ if (ratings[len-i-1]>ratings[len-i]){ candyNum[len-i-1] = std::max(candyNum[len-i]+1,candyNum[len-i-1]); } } return std::accumulate(candyNum.begin(), candyNum.end(), len); } };
Tips:
大体思路是greedy。题目的需求可以分解为如下两个条件:
a. ratings从左向右的子递增序列,candy也要是递增的
b. ratings从右向左的子递增序列,candy同样也是递增的
具体:
1. 从左往右遍历一次,保证从左→右的递增序列,candy都是递增1的(相当于先对条件a进行了一次greedy,保证了条件a是充分的)
2. 从右往左遍历一次,保证从右→左的递增序列,candy也是至少递增1的(相当于再对条件b进行了一次greedy,保证了条件b是充分的,但是不能破坏条件a成立)
代码中一条关键语句如下:
std::max(candyNum[len-i]+1,candyNum[len-i-1]);
举个例子,ratings = {4,2,3,4,1}
从左往右走完第一遍 则candyNum = {0,0,1,2,0}
现在开始从右往左走,如果没有max这条语句,则走完右数第二个元素就变成了 candyNum = {0,0,1,1,0}
这样为了满足条件b就破坏了条件a,所以max这条语句是必要的。
从总体思路上来说:两个greedy并不能直接得到全局的最优解,需要调节两个greedy之间的矛盾,而max这条语句就是调节矛盾的。
================================================
第二次过这道题,大体思路记得比较清楚,就是红字的部分,两个greedy之间不能破坏彼此的条件。
class Solution { public: int candy(vector<int>& ratings) { vector<int> candys(ratings.size(),1); // from left to right for ( int i=1; i<ratings.size(); ++i ) { if ( ratings[i]>ratings[i-1] ) candys[i] = candys[i-1]+1; } // from right to left for ( int i=ratings.size()-1; i>0; --i ) { if ( ratings[i-1]>ratings[i] ) { candys[i-1] = std::max( candys[i-1], candys[i]+1 ); } } return accumulate(candys.begin(), candys.end(), 0); } };