AlgoMaster Logo

Candy

Last Updated: March 29, 2026

hard
4 min read

Understanding the Problem

We have a line of children, each with a rating. We need to hand out candies so that every child gets at least one, and any child whose rating is strictly higher than an immediate neighbor gets more candies than that neighbor. The goal is to minimize the total number of candies.

The tricky part is that each child has two neighbors (except the ones at the ends), and we need to satisfy the constraint in both directions simultaneously. If child 3 has a higher rating than both child 2 and child 4, then child 3's candy count must exceed both of those neighbors.

The key observation is that "higher rating means more candies" only applies to strict inequality. If two adjacent children have the same rating, there's no requirement that they have the same (or different) candy count. This detail catches a lot of people off guard.

Key Constraints:

  • 1 <= n <= 2 * 10^4 → With n up to 20,000, both O(n^2) and O(n) solutions should pass comfortably. But O(n) is the cleaner target.
  • 0 <= ratings[i] <= 2 * 10^4 → Ratings are non-negative integers. Two children can have the same rating.

Approach 1: Brute Force (Iterative Correction)

Intuition

The most straightforward idea: start by giving every child 1 candy, then keep scanning the array and fixing violations until there are none left. A violation is any position where a child has a higher rating than a neighbor but doesn't have more candies. When we find one, we bump that child's candy count up.

This is conceptually simple but wasteful. Each correction pass might introduce new issues (bumping one child might create a new violation with their other neighbor), so we might need multiple passes before everything stabilizes.

Algorithm

  1. Initialize a candies array of size n, with every element set to 1.
  2. Set a flag changed = true.
  3. While changed is true:
    • Set changed = false.
    • For each child i from 0 to n-1:
      • If ratings[i] > ratings[i-1] and candies[i] <= candies[i-1], set candies[i] = candies[i-1] + 1 and mark changed = true.
      • If ratings[i] > ratings[i+1] and candies[i] <= candies[i+1], set candies[i] = candies[i+1] + 1 and mark changed = true.
  4. Return the sum of the candies array.

Example Walkthrough

Input:

0
1
1
0
2
2
ratings

Pass 1: Check each child. Child 0 has rating 1 > child 1's rating 0, but candies[0]=1 <= candies[1]=1, so bump candies[0] to 2. Child 2 has rating 2 > child 1's rating 0, but candies[2]=1 <= candies[1]=1, so bump candies[2] to 2. Result:

0
2
1
1
2
2
candies

Pass 2: No violations found. Done. Total = 2 + 1 + 2 = 5.

Code

Each pass through the array might only resolve a small number of violations. What if we decomposed the two-directional constraint into two one-directional passes?

Approach 2: Two-Pass Greedy

Intuition

The candy requirement is really two separate constraints glued together. The left constraint says: if ratings[i] > ratings[i-1], then candies[i] > candies[i-1]. The right constraint says: if ratings[i] > ratings[i+1], then candies[i] > candies[i+1].

A left-to-right pass can enforce the left constraint perfectly, because by the time we reach position i, we've already finalized position i-1. Similarly, a right-to-left pass can enforce the right constraint. At each position, the answer is the maximum of what the two passes require, because we need to satisfy both constraints simultaneously.

Algorithm

  1. Create a candies array of size n, initialized to all 1s.
  2. Left-to-right pass: For i from 1 to n-1, if ratings[i] > ratings[i-1], set candies[i] = candies[i-1] + 1.
  3. Right-to-left pass: For i from n-2 down to 0, if ratings[i] > ratings[i+1], set candies[i] = max(candies[i], candies[i+1] + 1).
  4. Return the sum of the candies array.

Example Walkthrough

1Input ratings array
0
1
1
3
2
5
3
3
4
2
5
1
1/8
1Initialize all candies to 1
0
1
1
1
2
1
3
1
4
1
5
1
1/8

Code

The two-pass approach is O(n) time, which is optimal. But it uses O(n) extra space. Can we compute the total without storing each child's candy count?

Approach 3: Single-Pass with Slope Counting (O(1) Space)

Intuition

If you look at the ratings array as a landscape, it's a series of "uphills" and "downhills." On an uphill (ratings increasing), candy counts go 1, 2, 3, ... On a downhill (ratings decreasing), candy counts go ..., 3, 2, 1. The question is what happens at the peaks.

We don't need to store every child's candy count. We can compute the total on-the-fly by tracking the lengths of ascending and descending runs. We track three values: up (ascending run length), down (descending run length), and peak (the ascending run length at the most recent peak). When the descending run exceeds peak, the peak child needs bumping, so we add 1 to the total.

Algorithm

  1. Initialize total = 1, up = 0, down = 0, peak = 0.
  2. For each position i from 1 to n-1:
    • If ratings[i] > ratings[i-1] (going up): increment up, reset down = 0, set peak = up, add up + 1 to total.
    • If ratings[i] < ratings[i-1] (going down): increment down, reset up = 0, add down to total. If down > peak, add 1 more.
    • If ratings[i] == ratings[i-1] (flat): reset up, down, peak to 0, add 1 to total.
  3. Return total.

Example Walkthrough

1Start: total=1 (child 0 gets 1), up=0, down=0, peak=0
0
1
start
1
3
2
5
3
3
4
2
5
1
1/7

Code