LeetCode 135: Candy (Two-Pass Greedy Rating Slopes)
LeetCode 135GreedyArrayTwo PassToday we solve LeetCode 135 - Candy.
Source: https://leetcode.com/problems/candy/
English
Problem Summary
Each child has a rating. You must give each child at least one candy, and children with a higher rating than an adjacent child must receive more candies. Return the minimum total candies.
Key Insight
Local constraints come from both directions. A single left-to-right pass misses right-neighbor pressure. So we compute left constraints, then right constraints, and take the max per position.
Brute Force and Limitations
A repeated relaxation simulation (keep adjusting neighbors until stable) can work but may degrade toward O(n^2). We can do this deterministically in two linear passes.
Optimal Algorithm Steps
1) Initialize candies[i] = 1 for all i.
2) Left to right: if ratings[i] > ratings[i-1], set candies[i] = candies[i-1] + 1.
3) Right to left: if ratings[i] > ratings[i+1], set candies[i] = max(candies[i], candies[i+1] + 1).
4) Sum all candies.
Complexity Analysis
Time: O(n).
Space: O(n).
Common Pitfalls
- Only scanning one direction.
- In the second pass, forgetting max and overwriting larger left-pass values.
- Mishandling equal ratings (they do not force strict inequality).
Reference Implementations (Java / Go / C++ / Python / JavaScript)
class Solution {
public int candy(int[] ratings) {
int n = ratings.length;
int[] candies = new int[n];
java.util.Arrays.fill(candies, 1);
for (int i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
candies[i] = candies[i - 1] + 1;
}
}
for (int i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
candies[i] = Math.max(candies[i], candies[i + 1] + 1);
}
}
int ans = 0;
for (int c : candies) ans += c;
return ans;
}
}func candy(ratings []int) int {
n := len(ratings)
candies := make([]int, n)
for i := range candies {
candies[i] = 1
}
for i := 1; i < n; i++ {
if ratings[i] > ratings[i-1] {
candies[i] = candies[i-1] + 1
}
}
for i := n - 2; i >= 0; i-- {
if ratings[i] > ratings[i+1] {
need := candies[i+1] + 1
if need > candies[i] {
candies[i] = need
}
}
}
ans := 0
for _, c := range candies {
ans += c
}
return ans
}class Solution {
public:
int candy(vector<int>& ratings) {
int n = ratings.size();
vector<int> candies(n, 1);
for (int i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
candies[i] = candies[i - 1] + 1;
}
}
for (int i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
candies[i] = max(candies[i], candies[i + 1] + 1);
}
}
int ans = 0;
for (int c : candies) ans += c;
return ans;
}
};class Solution:
def candy(self, ratings: list[int]) -> int:
n = len(ratings)
candies = [1] * n
for i in range(1, n):
if ratings[i] > ratings[i - 1]:
candies[i] = candies[i - 1] + 1
for i in range(n - 2, -1, -1):
if ratings[i] > ratings[i + 1]:
candies[i] = max(candies[i], candies[i + 1] + 1)
return sum(candies)var candy = function(ratings) {
const n = ratings.length;
const candies = new Array(n).fill(1);
for (let i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
candies[i] = candies[i - 1] + 1;
}
}
for (let i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
candies[i] = Math.max(candies[i], candies[i + 1] + 1);
}
}
return candies.reduce((a, b) => a + b, 0);
};中文
题目概述
每个孩子有一个评分。每人至少分到 1 颗糖;如果某个孩子评分高于相邻孩子,则他的糖果数必须更多。求最少需要多少糖果。
核心思路
约束同时来自左右两侧。只做一次单向遍历会漏掉另一侧的要求。正确做法是先处理“左约束”,再处理“右约束”,每个位置取更大值。
暴力解法与不足
可以反复扫描并修正相邻关系直到稳定,但最坏可能接近 O(n^2)。两次线性遍历即可一次性满足全部局部约束。
最优算法步骤
1)初始化 candies[i] = 1。
2)从左到右:若 ratings[i] > ratings[i-1],则 candies[i] = candies[i-1] + 1。
3)从右到左:若 ratings[i] > ratings[i+1],则 candies[i] = max(candies[i], candies[i+1] + 1)。
4)求和即答案。
复杂度分析
时间复杂度:O(n)。
空间复杂度:O(n)。
常见陷阱
- 只做单向扫描。
- 第二遍忘记取 max,把第一遍更大的值覆盖掉。
- 对评分相等处理错误(相等不要求更多糖果)。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
class Solution {
public int candy(int[] ratings) {
int n = ratings.length;
int[] candies = new int[n];
java.util.Arrays.fill(candies, 1);
for (int i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
candies[i] = candies[i - 1] + 1;
}
}
for (int i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
candies[i] = Math.max(candies[i], candies[i + 1] + 1);
}
}
int ans = 0;
for (int c : candies) ans += c;
return ans;
}
}func candy(ratings []int) int {
n := len(ratings)
candies := make([]int, n)
for i := range candies {
candies[i] = 1
}
for i := 1; i < n; i++ {
if ratings[i] > ratings[i-1] {
candies[i] = candies[i-1] + 1
}
}
for i := n - 2; i >= 0; i-- {
if ratings[i] > ratings[i+1] {
need := candies[i+1] + 1
if need > candies[i] {
candies[i] = need
}
}
}
ans := 0
for _, c := range candies {
ans += c
}
return ans
}class Solution {
public:
int candy(vector<int>& ratings) {
int n = ratings.size();
vector<int> candies(n, 1);
for (int i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
candies[i] = candies[i - 1] + 1;
}
}
for (int i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
candies[i] = max(candies[i], candies[i + 1] + 1);
}
}
int ans = 0;
for (int c : candies) ans += c;
return ans;
}
};class Solution:
def candy(self, ratings: list[int]) -> int:
n = len(ratings)
candies = [1] * n
for i in range(1, n):
if ratings[i] > ratings[i - 1]:
candies[i] = candies[i - 1] + 1
for i in range(n - 2, -1, -1):
if ratings[i] > ratings[i + 1]:
candies[i] = max(candies[i], candies[i + 1] + 1)
return sum(candies)var candy = function(ratings) {
const n = ratings.length;
const candies = new Array(n).fill(1);
for (let i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
candies[i] = candies[i - 1] + 1;
}
}
for (let i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
candies[i] = Math.max(candies[i], candies[i + 1] + 1);
}
}
return candies.reduce((a, b) => a + b, 0);
};
Comments