Solution 1
将整个问题解构,实际上就是一种贪心策略。
- 当前位置的取值只跟前后两个邻居相关
- 绝对升序列下,当前位置的糖果数目才会增加
基于这两个解构项,我们可以确定,任何一个局部最小值(允许相等)都可以只给1个糖果,那么相当于我们需要只找到一个个小山,每个山的左右两个端点(局部最小)一定是1,然后内部按照升序列递增计算,峰顶取最大结果的一侧。
【参考官方】官方题解形式化成双指针的设计,左右各遍历一次以寻找升序列,且每个位置初始化为1,因此可以直接更新结果,只是在从右往左遍历时,每个点的取值取决的二者方案的最大。
- 时间复杂度: O ( N ) O(N) O(N),其中 N N N为输入长度,三次线性遍历
- 空间复杂度: O ( N ) O(N) O(N),其中 N N N为输入长度,保存分配临时结果
class Solution {
public:
int candy(vector<int>& ratings) {
int num = ratings.size();
vector<int> candy(num, 1);
// 从左到右,检查升序列
for (int i = 1; i < num; ++i) {
if (ratings[i] > ratings[i - 1]) {
candy[i] = candy[i - 1] + 1;
}
}
// 从右到左,检查升序列,实际上就是降序列
for (int i = num - 2; i >=0 ; --i) {
if (ratings[i] > ratings[i + 1]) {
// 取两个序列下当前位置取值的最优方案
candy[i] = max(candy[i], candy[i + 1] + 1);
}
}
int ans = accumulate(candy.begin(), candy.end(), 0);
return ans;
}
};
Solution 2
【参考官方】继续对上一个分析进行简化:由于一个连续的绝对上升序列的糖果分配是一个等差递增序列,那么可以通过序列长度知道这个序列分配结果的总和,因此可以通过对状态的记录简化空间占用。
- 对方向的判断,简化成两个方向状态量,用二者的大小映射小山的位置
- 使用up和down分别描述小山的两条边
- 最后计数时,需要留意最大取值,以及边界情况下虚拟结点的引入
- 时间复杂度: O ( N ) O(N) O(N),其中 N N N为输入长度,三次线性遍历
- 空间复杂度: O ( N ) O(N) O(N),仅维护常数个状态量
class Solution {
public:
int candy(vector<int>& ratings) {
int ans = 0;
int up = 0;
int down = 0;
int dir = 0;
for (int i = 1; i < ratings.size(); ++i) {
// 判断方向
int tempDir = (ratings[i] > ratings[i - 1])? 1: (ratings[i] < ratings[i - 1])? -1: 0;
// 当前位置出现局部最小(允许相等)
if ((dir > 0 && tempDir == 0) || (dir < 0 && tempDir >= 0)) {
// 整理当前小山,最高位取两侧最大
ans += tempSum(up) + tempSum(down) + max(up, down);
up = 0;
down = 0;
}
// 从当前位置开始继续更新
if (tempDir > 0) {
// 当前升序
up++;
} else if (tempDir < 0) {
// 当前降序
down++;
} else {
// 平缓,仍然取1,且跳过小山计算
ans ++;
}
dir = tempDir;
}
// 最后结尾情况,虚拟化一个外部的最小结点
ans += tempSum(up) + tempSum(down) + max(up, down) + 1;
return ans;
}
int tempSum(int n) {
return n * (n + 1) / 2;
}
};
Solution 3
Solution 1的Python实现
class Solution:
def candy(self, ratings: List[int]) -> int:
num = len(ratings)
candy = [1] * num
for i in range(1, num):
if ratings[i] > ratings[i - 1]:
candy[i] = candy[i - 1] + 1
for i in range(num - 2, -1, -1):
if ratings[i] > ratings[i + 1]:
candy[i] = max(candy[i], candy[i + 1] + 1)
ans = sum(candy)
return ans
Solution 4
Solution 2的Python实现
class Solution:
def candy(self, ratings: List[int]) -> int:
num = len(ratings)
def tempSum(n):
return n * (n + 1) // 2
ans = 0
up, down = 0, 0
D = 0
for i in range (1, num):
tempDir = 1 if ratings[i] > ratings[i - 1] else -1 if ratings[i] < ratings[i - 1] else 0
if (D > 0 and tempDir == 0) or (D < 0 and tempDir >= 0):
ans += tempSum(up) + tempSum(down) + max(up, down)
up, down = 0, 0
if tempDir > 0: up += 1
elif tempDir < 0: down += 1
else: ans += 1
D = tempDir
ans += tempSum(up) + tempSum(down) + max(up, down) + 1
return ans