You teach a class of children sitting in a row, each of whom has a rating based on their performance. You want to distribute candies to the children while abiding by the following rules:
Determine the minimum number of candies you need to distribute to satisfy these conditions.
Input: ratings = [4, 3, 2, 4, 5, 1]
Output: 12
Explanation: You can distribute candies to each child as follows: [3, 2, 1, 2, 3, 1].
Input: ratings = [1, 3, 3]
Output: 4
Explanation: You can distribute candies to each child as follows: [1, 2, 1].
New to this one? Start here. Below is the core idea in everyday language, plus a real-world analogy—then the sections that follow build on it with the formal reasoning, code, and step-by-step walkthroughs.
Think of candies as salaries and ratings as performance. Nobody earns less than the baseline, and anyone who out-performs the person beside them must earn more than that person — but you want to spend as little as possible. The fair, cheapest solution looks at each neighbor separately and then takes the stricter of the two demands.
There are two independent demands on each child: “beat my left neighbor” and “beat my right neighbor.” Handle them in two separate passes — one left-to-right, one right-to-left — then take the maximum of the two requirements for each child. That maximum satisfies both sides at once.
For starters, we know we need to give at least 1 candy to each of the n children to satisfy the first requirement of this problem. As for the other requirement, let's start off by considering a few specific cases.
Uniform ratings
Consider the situation where all children have the same rating. Since no child has a higher rating than another, we can give each child one candy to meet both requirements.
Increasing ratings
Now, consider the case where the children’s ratings are in strictly increasing order. Here, each child should receive one more candy than their left-side neighbor.
The first child gets one candy because they have no left-side neighbor, and a smaller rating than their right-side neighbor. Each subsequent child has a higher rating than their left-side neighbor, so gets one more candy than that neighbor.
Decreasing ratings
Here, each child needs to receive one more candy than their right-side neighbor.
This is the same as the previous case, but in reverse. To populate the candies array in reverse, we start with the child furthest to the right, giving them one candy. Moving leftward, we give each child one more candy than their right-side neighbor:
Non-uniform ratings
Unlike previous cases, in a non-uniform distribution of ratings, children can have higher ratings than their left-side neighbor, right-side neighbor, both neighbors, or neither. This makes handling non-uniform ratings more complex.
What if we can handle these cases separately? Specifically, we could use:
One pass to ensure children with a higher rating than their left-side neighbor get more candy (handle increasing ratings).
A second pass to ensure children with a higher rating than their right-side neighbor get more candy (handle decreasing ratings).
This allows us to apply the logic we used for increasing and decreasing ratings in two separate passes. Let’s see if this strategy works over the following example, starting with an initial distribution of 1 candy for each child to ensure we meet the first requirement of this problem:
First pass: handle increasing ratings
Iterate through the ratings array and, for each child, check if they have a higher rating than their left-side neighbor (if ratings[i] > ratings[i - 1]). Start from index 1 since the child at index 0 doesn’t have a left-side neighbor.
If a child's rating is higher than their left-side neighbor's rating, make sure they have at least one more candy than their left-side neighbor (candies[i] = candies[i - 1] + 1).
Otherwise, just continue to the next child’s rating.
We can see how this process updates the candy distribution below:
Second pass: handle decreasing ratings
Iterate through the ratings array in reverse and, for each child, check if they have a higher rating than their right-side neighbor (if ratings[i] > ratings[i + 1]). Start at index 4 since the child at index 5 (the last child) doesn’t have a right-side neighbor.
If a child's rating is higher than their right-side neighbor's rating, make sure they have one more candy than that neighbor. Note that because we already did one pass through the candies array, they might already have more candies than their right-side neighbor, in which case the current amount of candy they have is sufficient.
Otherwise, continue to the next child’s rating.
We can see how this process updates the candy distribution below:
At the end of the second pass, each child should have the correct number of candies. Now, we just need to return the sum of all the candies in the candies array.
The solution we came up with is a greedy solution because it satisfies the greedy choice property: we make a locally optimal choice for the current child by only considering the ratings of their immediate neighbors, without worrying about the ratings of other children.
How can we be sure this strategy works? Over our two passes, we ensure both the left-side and right-side neighbors of each child are considered when distributing candies. This guarantees that the solution meets the problem's requirements.
from typing import List
def candies(ratings: List[int]) -> int:
n = len(ratings)
# Ensure each child starts with 1 candy.
candies = [1] * n
# First pass: for each child, ensure the child has more candies than their
# left-side neighbor if the current child's rating is higher.
for i in range(1, n):
if ratings[i] > ratings[i - 1]:
candies[i] = candies[i - 1] + 1
# Second pass: for each child, ensure the child has more candies than their
# right-side neighbor if the current child's rating is higher.
for i in range(n - 2, -1, -1):
if ratings[i] > ratings[i + 1]:
# If the current child already has more candies than their right-side
# neighbor, keep the higher amount.
candies[i] = max(candies[i], candies[i + 1] + 1)
return sum(candies)#include <vector>
#include <algorithm>
using namespace std;
int candies(vector<int>& ratings) {
int n = (int)ratings.size();
vector<int> candy(n, 1);
// Pass 1 (left to right): satisfy the left-neighbor rule.
for (int i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
candy[i] = candy[i - 1] + 1;
}
}
// Pass 2 (right to left): satisfy the right-neighbor rule too.
for (int i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
// Keep whichever is larger so BOTH rules stay satisfied.
candy[i] = max(candy[i], candy[i + 1] + 1);
}
}
int total = 0;
for (int i = 0; i < n; i++) {
total += candy[i];
}
return total;
}// These methods live inside a class, e.g. class Solution { ... }
int candies(int[] ratings) {
int n = ratings.length;
int[] candy = new int[n];
java.util.Arrays.fill(candy, 1);
// Pass 1 (left to right): satisfy the left-neighbor rule.
for (int i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
candy[i] = candy[i - 1] + 1;
}
}
// Pass 2 (right to left): satisfy the right-neighbor rule too.
for (int i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
// Keep whichever is larger so BOTH rules stay satisfied.
candy[i] = Math.max(candy[i], candy[i + 1] + 1);
}
}
int total = 0;
for (int i = 0; i < n; i++) {
total += candy[i];
}
return total;
}Time complexity: The time complexity of candies is because we perform two passes over the nums array.
Space complexity: The space complexity is due to the space taken up by the candies array.
Two step-by-step walkthroughs of the algorithm below: a valid case (the expected happy path) and an invalid / edge case that exercises the tricky parts. Each step shows the program state as the code runs—the same steps apply to Python, C++ and Java.
Everyone starts at 1. Pass 1 fixes uphills going right; pass 2 fixes uphills going left, taking the max.
| pass | rule | candy[4] |
|---|---|---|
| 1 (L→R) | 5 > 4 → left+1 | 3 |
| 2 (R→L) | 5 > 1 → max(3, 1+1) | 3 |
Sum of [3, 2, 1, 2, 3, 1] = 12. ✓
Equal ratings impose no constraint on each other — only strictly higher triggers the rule. So the two equal 3s need not match.
| comparison | strictly higher? | effect |
|---|---|---|
| ratings[1]=3 vs [0]=1 | yes | candy[1] = 2 |
| ratings[2]=3 vs [1]=3 | no (equal) | candy[2] stays 1 |
Sum of [1, 2, 1] = 4. Equal ratings are free of each other. ✗
sum(candy) finishes it; the two loops go in opposite directions.
Name the array candy so it does not clash with the function candies; totals fit in int.
Arrays.fill(candy, 1) sets the baseline; Math.max guards the second pass.