您的位置:首页 > 其它

leecode 解题总结:135. Candy

2017-02-17 23:13 260 查看
#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
using namespace std;
/*
问题:
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 value排名。
N个孩子站成一排,每个人被分配了一个排名值。你需要给孩子分配糖果:
每个孩子至少有一个糖果,较高排名的孩子需要比他的邻居都要多。
这里第二点有歧义,较高排名的比左边较低排名的多,比右边较低排名的多。
举例:
r:1 5 2 4 3
设n个人每个人分配的糖果为x[i],i从1到N
根据当前题目:
x[1] < x[2]
x[2] > x[3]
x[3] < x[4]
x[4] > x[5]
难点在于不知道从哪个地方选取赋予最少的糖果,假设我们选取排名最小的第一个孩子,发一个糖果
那么x[1]=1,根据关系式:x[2] >= 2,
x[3] <= 1,
x[4] >= 2
x[5] <= 1
综上,最少糖果为: 1 + 2 + 1 + 2 + 1 = 7
假设是:
r:1 2 3 4 5
则糖果至少为:1 + 2 + 3 + 4 + 5 = 15
如果是:
r:5 4 3 2 1
糖果也是:5 + 4 + 3 + 2 + 1 = 15
如果是:
r:4 2 1 3 5,
那么糖果是: 3 + 2 + 1 + 2 + 3 = 11
r:4 3 1 5 3
糖果是: 3 + 2 + 1 + 2 + 1 = 9
发现:将一个高排名的左右安排比他排名低的,比一直按排名升序或降序排列好
如果仅仅是给定排名,我们可以得到一个关系式,利用关系式来推出当前第i个孩子,
至少要分配多少糖果。
顺序可以从前向后递推。
如果是: 1 2 6 5 4 3,那么就需要: 1 + 2 + 4 + 3 + 2 + 1 = 13
也就是可以确定发送糖果最多的个数= 寻找到的排名单调增区间或者单调减区间的最大长度
以1 2 6 5 4 3为例找到最大单调递增区间是{1,2,6},最大单调减区间是{6,5,4,3},
所以发给的糖果个数等于4,将该最长的单调增区间或减区间
左右分成两半,对左边继续上述操作,对右边继续寻找上述操作
累加结果。这个应该是分治算法。
如果出现多个相同长度的单调区间,随便选择一个,即可。
dp[i][j]表示从A[i...j]花费的最少糖果数
分析时间复杂度:每次先要找到当前部分中长度最长的单调区间,耗时O(n),
然后将数组分成左边和右边,对左边和右边重复上述过程
总的时间复杂度为O(n^2)

竟然有排名相同的,排名相同的可以给相同的糖果。这个不影响给出的单人最高糖果数量
我需要修改的地方:

比如给定的是
1 1 2 2 3 3:那么长度为6,但是不重复元素数量为3,最高糖果数为3,然后还得遍历一把

输入:
6
1 2 6 5 4 3
5
1 2 3 4 5
5
1 5 2 4 3
12
12 9 2 7 8 6 5 3 4 1 11 10
11
10 9 2 7 8 6 5 10 3 1 11
1
1
2
2 2

3
1 2 2
输出:
13
15
7
23
20
1
2
4

报错:
Input:[1,2,2]
Output:5
Expected:4
为什么?

别人的解法:http://www.cnblogs.com/AndyJee/p/4483043.html
关键:
1
可以从题目角度来看:从前到后,如果后面人排名比前面人高,后面人给的糖果数=前面一个人给的糖果数+1
但是后面<=前面的情况无法判断,我们暂时不处理。
然后从后向前,每个元素与其后面的元素比较,如果ratings[i] > ratings[i+1],且
令candy[i] = max(candy[i] , ratings[i+1]+1),因为至少要比后面的人多1
题目中没有说明如果两个人排名相同是否需要给相同数量的糖果,所以1,2,2.只需要1 + 2 + 1共4颗。

2 典型的双向贪心算法
*/

class Solution {
public:
int candy(vector<int>& ratings)
{
if(ratings.empty())
{
return 0;
}
if(ratings.size() <= 1)
{
return 1;
}
int size = ratings.size();
vector<int> candyNum(size , 1);//初始化每个人至少一个糖果
for(int i = 1 ; i < size ; i++)
{
//如果从前向后遍历,元素>前面元素,则元素的糖果数=前面元素的糖果数+1
if(ratings.at(i) > ratings.at(i-1))
{
candyNum.at(i) = candyNum.at(i-1) + 1;
}
}
//从后向前遍历, 当前元素>后面元素,则当前元素糖果数=max(当前元素糖果数,后面元素糖果数+1),
//取较大值,才能满足比两边相邻较小排名分得的糖果数更多一点
int result = candyNum.at(size - 1);
//逆序遍历,i--
for(int i = size - 2; i >= 0; i--)
{
if(ratings.at(i) > ratings.at(i+1))
{
candyNum.at(i) = max(candyNum.at(i) , candyNum.at(i+1) + 1);
}
result += candyNum.at(i);
}
return result;
}
};

void print(vector<int>& result)
{
if(result.empty())
{
cout << "no result" << endl;
return;
}
int size = result.size();
for(int i = 0 ; i < size ; i++)
{
cout << result.at(i) << " " ;
}
cout << endl;
}

void process()
{
vector<int> nums;
int value;
int num;
Solution solution;
vector<int> result;
while(cin >> num )
{
nums.clear();
for(int i = 0 ; i < num ; i++)
{
cin >> value;
nums.push_back(value);
}
num = solution.candy(nums);
cout << num << endl;
}
}

int main(int argc , char* argv[])
{
process();
getchar();
return 0;
}

/*
public:
//计算某个单调区间的总糖果数,以及最高糖果数
int calculate(vector<int>& ratings , int beg , int end, bool isIncreasing)
{
if(ratings.empty() || beg < 0 || end >= ratings.size() || beg > end)
{
return 0;
}
//如果只有一个元素,直接返回1
if(beg == end)
{
return 1;
}

int result = 0;
int curNum;
//如果是递增的
if(isIncreasing)
{
result = 1;
curNum = 1;
for(int i = beg + 1 ; i <= end ; i++)
{
//后面不等于前面
if(ratings.at(i) != ratings.at(i-1))
{
curNum++;
}
//相同元素,curNum不变,
result += curNum;
}
}
else
{
result = 1;
curNum = 1;
for(int i = end - 1 ; i >= beg ; i--)
{
//后面不等于前面
if(ratings.at(i) != ratings.at(i+1))
{
curNum++;
}
//相同元素,curNum不变,
result += curNum;
}
}
return result;
}

int getCandy(vector<int>& ratings , int beg , int end)
{
if(ratings.empty() || beg < 0 || end >= ratings.size() || beg > end)
{
return 0;
}
//如果只有一个元素,直接返回1
if(beg == end)
{
return 1;
}
//如果剩余部分从beg到end为单调增区间或减区间,直接返回结果是从1到end-beg的累加和
int decrementBeg = beg;
int decrementEnd = beg;
int incrementBeg = beg;
int incrementEnd = beg;
int realDecrementBeg = beg;
int realDecrementEnd = beg;
int realIncrementBeg = beg;
int realIncrementEnd = beg;
int maxIncrementLen = 1;
int maxDecrementLen = 1;
//先计算从beg到end中最长单调增区间和单调减区间,需要记录各自的下标
for(int i = beg + 1 ; i <= end ; i++)
{
//寻找最长单调增区间,相同的元素也包含进来
if(ratings.at(i) >= ratings.at(i-1))
{
incrementEnd = i;
}
//说明后面比前面小,是单调减区间,此时应该计算单调增区间的长度,如果遇到相同的元素,不算
else
{
if(incrementEnd - incrementBeg + 1 > maxIncrementLen)
{
maxIncrementLen = incrementEnd - incrementBeg + 1 ;
realIncrementBeg = incrementBeg;
realIncrementEnd = incrementEnd;
}
//需要重新设定单调增区间的起始点和结束点为当前
incrementEnd = incrementBeg = i;
}

//寻找最长单调增区间
if(ratings.at(i) <= ratings.at(i-1))
{
//累加单调减区间的结束值
decrementEnd = i;
}
//说明后面比前面小,是单调减区间,此时应该计算单调增区间的长度
else
{
//计算单调减区间的长度
if( decrementEnd - decrementBeg + 1 > maxDecrementLen)
{
maxDecrementLen = decrementEnd - decrementBeg + 1;
realDecrementBeg = decrementBeg;
realDecrementEnd = decrementEnd;
}
//更新单调减区间的起始值为当前下标
decrementBeg = decrementEnd = i;
}
}
//可能存在一种情况,一直到最后一个元素都一直降序或升序,导致遗漏一次,需要计算
if(incrementEnd - incrementBeg + 1 > maxIncrementLen)
{
maxIncrementLen = incrementEnd - incrementBeg + 1 ;
realIncrementBeg = incrementBeg;
realIncrementEnd = incrementEnd;
}
if( decrementEnd - decrementBeg + 1 > maxDecrementLen)
{
maxDecrementLen = decrementEnd - decrementBeg + 1;
realDecrementBeg = decrementBeg;
realDecrementEnd = decrementEnd;
}

//比较单调增区间和单调减区间谁的长度长,就选择谁的长度作为最高糖果数,并将区间划分
int realBeg;
int realEnd;
int maxLen = max(maxIncrementLen , maxDecrementLen);

//判断从beg到end是否一直是升序或降序,如果是,就直接计算出结果并返回
if(maxLen == end - beg + 1)
{
int sum = 0;
if(maxLen == maxIncrementLen)
{
sum = calculate(ratings , beg , end , true);
}
else
{
sum = calculate(ratings , beg , end , false);
}
return sum;
}

if( maxIncrementLen > maxDecrementLen)
{
realBeg = realIncrementBeg;
realEnd = realIncrementEnd;
}
else
{
realBeg = realDecrementBeg;
realEnd = realDecrementEnd;
}
//将区间划分成左右不分,
int leftResult = getCandy(ratings , beg , realBeg - 1);
int rightResult = getCandy(ratings , realEnd + 1 , end);
int result = 0;
if(maxLen == maxIncrementLen)
{
result = calculate(ratings , realBeg, realEnd , true);
}
else
{
result = calculate(ratings , realBeg, realEnd , false);
}
result += leftResult + rightResult;
return result;
}

int candy(vector<int>& ratings) {
if(ratings.empty())
{
return 0;
}
int result = getCandy(ratings , 0 , ratings.size() - 1);
return result;
}
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: