您的位置:首页 > 其它

leetcode:candy

2014-09-12 10:39 369 查看
题目:https://oj.leetcode.com/problems/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?
题目意思是一群小孩站成一列,每个小孩有一个值rating,给小孩们分发糖果,需要满足两个条件:
1,每个小孩至少有一个糖果

2,rating比较高的小孩要比他旁边的小孩拿到的糖果多

刚开始还以为是和素数环一样的问题...仔细看了看发现没有思路...菜鸟渣渣不会做==

所以上网查了别人的解题报告,发现了一个巧妙的解法,只需要两遍遍历数组,时间复杂度为O(N)就可以解决了。

解题思路:

1,首先给数组每个元素赋值为1

vector<int> candyNum(ratings.size(),1);

2,先向右遍历一遍数组,如果后面的rating比较大就给后面的小孩多分配一个糖果;

3,再向左遍历一遍数组,如果前面的rating比较大,令cur = 后面的小孩的糖果数 + 1,如果cur比之前的candyNum[i]要大,则将candyNum[I]的值赋值为cur。

4,然后再把所有值相加即可。

但是有人会问,为什么这样两次扫描就能保证比两边都大?

其实仔细想想就可以发现,第一次扫描找出了向右的相邻的最长上升子序列;而第二次扫描找出的是向左的相邻最长上升子序列而且和之前的向右扫描时候的赋值做了比较,得到的是最大的那个结果。所以这样的解法是能够保证rating大的得到的糖果比两边都多,而且糖果总数最少。

我觉得这个解题思路还挺巧妙的,如果以后遇到这种需要考虑和左右数据相关的题目可以尝试使用这种思路考虑一下。

AC代码:

class Solution {
public:
int candy(vector<int> &ratings) {
int len = ratings.size();
vector<int> candyNum(len,1);

for(int i = 1;i < len;i++){
if(ratings[i] > ratings[i - 1]){
candyNum[i] = candyNum[i - 1] + 1;
}
}

//res为返回值,因为第二遍扫描时每一个小孩的糖果数已经确定所以可以在扫描的同时计算出结果
int res = candyNum[len - 1];
int cur;
for(int i = len - 2;i >= 0;i--){
if(ratings[i] > ratings[i + 1]){
cur = candyNum[i + 1] + 1;
//取向左和向右扫描时比较大的值作为小孩最后得到的糖果数
candyNum[i] = cur > candyNum[i] ? cur : candyNum[i];
}
res += candyNum[i];
}
return res;
}
//整个解题思路是在于:先向右扫描一遍数组,如果后面的rating比较大就比前面的小孩多分配一个糖果
//再向左扫描一遍数组,如果前面的rating比较大就比后面的小孩多分配一个糖果
//这样能保证小孩是在处于最长上升序列中的赋值
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: