一、问题描述
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?
Example 1:
Input: [1,0,2]
Output: 5
Explanation: You can allocate to the first, second and third child with 2, 1, 2 candies respectively.
Example 2:
Input: [1,2,2]
Output: 4
Explanation: You can allocate to the first, second and third child with 1, 2, 1 candies respectively.
The third child gets 1 candy because it satisfies the above two conditions.
二、问题分析
本周选题是LeetCode上面一道难度为Hard的135题–Candy。这道题之所以是Hard难度,并不是因为代码量大或者实现困难,而是算法很精巧。由于我是按照Tag为Greedy去检索得到的题,因此自然而然我们应该考虑如何用贪心算法去实现。
题目要求每个等级高的孩子的糖数必须必他的邻居高,却没有规定如果两个等级相同邻居的糖数是怎样的。考虑初始化所有孩子一开始都只有一颗糖,如果他比他前面的孩子等级高,那么他的糖数就定为前一个孩子的糖数+1。这样从前到后扫描一次,我们即可得到每个等级更高的孩子都比他前面孩子的糖数多。
类似,再从后面向前扫描一遍,如果前面的孩子比他后面孩子等级高,并且他的糖数不多于后面的孩子,那么我们设置他的糖数为后面孩子的糖数+1。这样从后向前扫描一遍,每个等级更高的孩子都比他后面孩子的糖数多;于此同时,这样设置并不会破坏之前从前向后扫描的逻辑(每个等级更高的孩子都比他前面孩子的糖数多)。
这样经过两次扫描,每个等级高的孩子的糖数也就比他两个邻居的都高了。因此我们也就得到了最终结果。这样的算法复杂度为O(n)(两次遍历数组即可)。
三、问题求解
针对问题分析,以下是c++源代码。
class Solution {
public:
int candy(vector<int>& ratings) {
int size = ratings.size();
int result[size];
for (int i = 0; i < size; i++) {
result[i] = 1;
}
for (int i = 1; i < size; i++) {
if (ratings[i] > ratings[i - 1]) {
result[i] = result[i - 1] + 1;
}
}
for (int i = size - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1] && result[i] <= result[i + 1]) {
result[i] = result[i + 1] + 1;
}
}
int total = 0;
for (int i = 0; i < size; i++) {
total += result[i];
}
return total;
}
};