The Candy problem from LeetCode is as follows:
There are n
children standing in a line. Each child is assigned a rating value given in an integer array ratings
, where ratings[i]
represents the rating of the i
-th child.
You are to distribute candies to these children following two rules:
Find and return the minimum number of candies required to distribute to all the children.
Constraints:
n
≤ 2 × 104ratings[i]
is an integer
At first glance, distributing candies based on the ratings might seem to require checking every possible way to assign candies, but that quickly becomes infeasible as n
grows.
The brute-force approach would be to try all possible distributions that satisfy the rules, but this is extremely inefficient. Instead, let's look for patterns and optimizations:
If we process the array from left to right, we can ensure that each child has more candies than their left neighbor if their rating is higher. But this doesn't guarantee the right neighbor constraint. So, we need a way to process both left and right neighbor relationships.
This leads to the idea of making two passes: one left-to-right and one right-to-left, adjusting candies accordingly.
To solve the problem efficiently, we follow these steps:
candies
array of the same length as ratings
, initializing all values to 1 (since each child must get at least one candy).candies[i] = max(candies[i], candies[i+1] + 1)
to preserve any previous increases from the left-to-right pass.candies
array to get the minimum total candies needed.This approach ensures that both neighbor constraints are satisfied for every child.
Let's take an example: ratings = [1, 0, 2]
candies = [1, 1, 1]
candies = [1, 1, 2]
candies = [2, 1, 2]
The minimum number of candies required is 5.
Brute-Force Approach:
n
.The optimized approach is efficient and suitable for large input sizes.
The Candy problem requires distributing candies so that each child gets at least one, and children with higher ratings than their immediate neighbors get more candies. By initializing all candies to one, then making two passes (left-to-right and right-to-left) to enforce the constraints, we can efficiently find the minimum total candies needed. The two-pass algorithm is both simple and elegant, ensuring all rules are satisfied with optimal time and space efficiency.
class Solution:
def candy(self, ratings):
n = len(ratings)
candies = [1] * n
# Left to right pass
for i in range(1, n):
if ratings[i] > ratings[i-1]:
candies[i] = candies[i-1] + 1
# Right to left pass
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)
class Solution {
public:
int candy(vector<int>& ratings) {
int n = ratings.size();
vector<int> candies(n, 1);
// Left to right pass
for (int i = 1; i < n; ++i) {
if (ratings[i] > ratings[i - 1])
candies[i] = candies[i - 1] + 1;
}
// Right to left pass
for (int i = n - 2; i >= 0; --i) {
if (ratings[i] > ratings[i + 1])
candies[i] = max(candies[i], candies[i + 1] + 1);
}
int total = 0;
for (int c : candies) total += c;
return total;
}
};
class Solution {
public int candy(int[] ratings) {
int n = ratings.length;
int[] candies = new int[n];
Arrays.fill(candies, 1);
// Left to right pass
for (int i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
candies[i] = candies[i - 1] + 1;
}
}
// Right to left pass
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 total = 0;
for (int c : candies) total += c;
return total;
}
}
var candy = function(ratings) {
const n = ratings.length;
const candies = new Array(n).fill(1);
// Left to right pass
for (let i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
candies[i] = candies[i - 1] + 1;
}
}
// Right to left pass
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);
};