โ† Back to All Algorithms

Hard Interview Frequency: โญโญโญ

Candy

Distribute candies to children based on ratings so that each child gets at least one candy, and children with higher ratings than immediate neighbors get more candies.

๐Ÿ“š Table of Contents

  1. Problem Statement
  2. Real-World Analogy
  3. Key Insights
  4. Solution Approaches
  5. Step-by-Step Walkthrough
  6. Complexity Analysis
  7. Edge Cases
  8. Test Cases
  9. Interview Tips
  10. Key Takeaways

๐Ÿ“‹ Problem Statement

You are given an integer array ratings. Assign candies to each child such that:

Return the minimum total candies needed.

Examples

Example 1:
Input: ratings = [1,0,2]
Output: 5
Distribution: [2,1,2]
Example 2:
Input: ratings = [1,2,2]
Output: 4
Distribution: [1,2,1]

Constraints

๐ŸŽฏ Real-World Analogy

Performance Bonus Seating Row

Imagine a row of teammates receiving bonus points. Everyone gets at least 1 point. If someone performed better than their immediate neighbor, they must receive more points.

One pass left-to-right handles "better than left neighbor". Another pass right-to-left handles "better than right neighbor". Combining both satisfies both constraints with minimal inflation.

๐Ÿ’ก Key Insights

๐Ÿ’ป Solution Approaches

Approach 1: Repeated Relaxation

Time: O(Nยฒ) worst case | Space: O(N)

Repeatedly scan and fix violations until stable. Correct but too slow and overcomplicated.

Approach 2: Two-Pass Greedy (Recommended)

Time: O(N) | Space: O(N)

Enforce left constraints in first pass, right constraints in second pass.

Python Implementation

from typing import List def candy(ratings: List[int]) -> int: """ Return minimum candies satisfying neighbor constraints. Time: O(N) Space: O(N) """ n = len(ratings) candies = [1] * n # Left to right: enforce ratings[i] > ratings[i-1] for i in range(1, n): if ratings[i] > ratings[i - 1]: candies[i] = candies[i - 1] + 1 # Right to left: enforce ratings[i] > ratings[i+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)

JavaScript Implementation

function candy(ratings) { /** * Return minimum candies satisfying neighbor constraints. * * Time: O(N) * Space: O(N) */ const n = ratings.length; const candies = new Array(n).fill(1); // Left to right for (let i = 1; i < n; i++) { if (ratings[i] > ratings[i - 1]) { candies[i] = candies[i - 1] + 1; } } // Right to left 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((sum, value) => sum + value, 0); }

๐Ÿ” Step-by-Step Walkthrough

Trace ratings = [1,0,2]:

Init: candies = [1, 1, 1]

Left pass:
i=1: 0 > 1? no -> [1,1,1]
i=2: 2 > 0? yes -> candies[2]=2 -> [1,1,2]
Right pass:
i=1: 0 > 2? no -> [1,1,2]
i=0: 1 > 0? yes -> candies[0]=max(1,1+1)=2 -> [2,1,2]
Total: 2 + 1 + 2 = 5

โšก Complexity Analysis

Time Complexity: O(N)

Two linear passes over ratings, each O(N).

Space Complexity: O(N)

We store one candy count per child.

๐Ÿ”ง Edge Cases

๐Ÿงช Test Cases

Python

def test_candy(): assert candy([1, 0, 2]) == 5 assert candy([1, 2, 2]) == 4 assert candy([1]) == 1 assert candy([1, 1, 1]) == 3 assert candy([1, 2, 3, 4]) == 10 assert candy([4, 3, 2, 1]) == 10 assert candy([1, 3, 2, 2, 1]) == 7 print("โœ… all tests passed")

JavaScript

function testCandy() { console.assert(candy([1, 0, 2]) === 5, "test 1"); console.assert(candy([1, 2, 2]) === 4, "test 2"); console.assert(candy([1]) === 1, "test 3"); console.assert(candy([1, 1, 1]) === 3, "test 4"); console.assert(candy([1, 2, 3, 4]) === 10, "test 5"); console.assert(candy([4, 3, 2, 1]) === 10, "test 6"); console.assert(candy([1, 3, 2, 2, 1]) === 7, "test 7"); console.log("โœ… all tests passed"); }

๐Ÿ’ผ Interview Tips

๐ŸŽ“ Key Takeaways

โ† Back to All Algorithms