🧠
Two-Pass Greedy with Left-to-Right and Right-to-Left Arrays
💡 This approach improves efficiency by using two passes to enforce constraints from both directions separately, then combining results. It is a classic greedy technique that beginners must master for array problems with neighbor constraints.
Intuition
Assign candies from left to right ensuring each child has more candies than the left neighbor if rating is higher. Then assign candies from right to left similarly. The final candies for each child is the max of the two passes.
Algorithm
- Initialize two arrays left2right and right2left with 1 candy each.
- Traverse ratings from left to right: if rating[i] > rating[i-1], left2right[i] = left2right[i-1] + 1.
- Traverse ratings from right to left: if rating[i] > rating[i+1], right2left[i] = right2left[i+1] + 1.
- For each child, assign candies as max(left2right[i], right2left[i]).
- Sum all candies and return the total.
💡 The two arrays capture constraints from each direction independently, and taking max ensures both neighbors' conditions are met.
def candy(ratings):
n = len(ratings)
left2right = [1] * n
right2left = [1] * n
for i in range(1, n):
if ratings[i] > ratings[i - 1]:
left2right[i] = left2right[i - 1] + 1
for i in range(n - 2, -1, -1):
if ratings[i] > ratings[i + 1]:
right2left[i] = right2left[i + 1] + 1
return sum(max(left2right[i], right2left[i]) for i in range(n))
# Driver code
if __name__ == '__main__':
print(candy([1, 0, 2])) # Output: 5
print(candy([1, 2, 2])) # Output: 4
Line Notes
left2right = [1] * nInitialize candies from left pass with minimum 1 candy each
right2left = [1] * nInitialize candies from right pass with minimum 1 candy each
for i in range(1, n)Left to right pass to enforce increasing rating constraint
if ratings[i] > ratings[i - 1]Check if current rating is higher than left neighbor
left2right[i] = left2right[i - 1] + 1Assign one more candy than left neighbor
for i in range(n - 2, -1, -1)Right to left pass to enforce increasing rating constraint from right
if ratings[i] > ratings[i + 1]Check if current rating is higher than right neighbor
right2left[i] = right2left[i + 1] + 1Assign one more candy than right neighbor
sum(max(left2right[i], right2left[i]) for i in range(n))Combine both passes by taking max candies needed for each child
import java.util.*;
public class Candy {
public static int candy(int[] ratings) {
int n = ratings.length;
int[] left2right = new int[n];
int[] right2left = new int[n];
Arrays.fill(left2right, 1);
Arrays.fill(right2left, 1);
for (int i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
left2right[i] = left2right[i - 1] + 1;
}
}
for (int i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
right2left[i] = right2left[i + 1] + 1;
}
}
int sum = 0;
for (int i = 0; i < n; i++) {
sum += Math.max(left2right[i], right2left[i]);
}
return sum;
}
public static void main(String[] args) {
System.out.println(candy(new int[]{1, 0, 2})); // 5
System.out.println(candy(new int[]{1, 2, 2})); // 4
}
}
Line Notes
Arrays.fill(left2right, 1);Initialize left to right candies with 1 candy each
Arrays.fill(right2left, 1);Initialize right to left candies with 1 candy each
for (int i = 1; i < n; i++)Left to right pass to assign candies based on left neighbor
if (ratings[i] > ratings[i - 1])Check if current rating is higher than left neighbor
left2right[i] = left2right[i - 1] + 1;Assign one more candy than left neighbor
for (int i = n - 2; i >= 0; i--)Right to left pass to assign candies based on right neighbor
if (ratings[i] > ratings[i + 1])Check if current rating is higher than right neighbor
right2left[i] = right2left[i + 1] + 1;Assign one more candy than right neighbor
sum += Math.max(left2right[i], right2left[i]);Take max candies needed from both passes
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int candy(vector<int>& ratings) {
int n = ratings.size();
vector<int> left2right(n, 1);
vector<int> right2left(n, 1);
for (int i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
left2right[i] = left2right[i - 1] + 1;
}
}
for (int i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
right2left[i] = right2left[i + 1] + 1;
}
}
int sum = 0;
for (int i = 0; i < n; i++) {
sum += max(left2right[i], right2left[i]);
}
return sum;
}
int main() {
vector<int> ratings1 = {1, 0, 2};
cout << candy(ratings1) << "\n"; // 5
vector<int> ratings2 = {1, 2, 2};
cout << candy(ratings2) << "\n"; // 4
return 0;
}
Line Notes
vector<int> left2right(n, 1);Initialize left to right candies with 1 candy each
vector<int> right2left(n, 1);Initialize right to left candies with 1 candy each
for (int i = 1; i < n; i++)Left to right pass to assign candies based on left neighbor
if (ratings[i] > ratings[i - 1])Check if current rating is higher than left neighbor
left2right[i] = left2right[i - 1] + 1;Assign one more candy than left neighbor
for (int i = n - 2; i >= 0; i--)Right to left pass to assign candies based on right neighbor
if (ratings[i] > ratings[i + 1])Check if current rating is higher than right neighbor
right2left[i] = right2left[i + 1] + 1;Assign one more candy than right neighbor
sum += max(left2right[i], right2left[i]);Take max candies needed from both passes
function candy(ratings) {
const n = ratings.length;
const left2right = new Array(n).fill(1);
const right2left = new Array(n).fill(1);
for (let i = 1; i < n; i++) {
if (ratings[i] > ratings[i - 1]) {
left2right[i] = left2right[i - 1] + 1;
}
}
for (let i = n - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) {
right2left[i] = right2left[i + 1] + 1;
}
}
let sum = 0;
for (let i = 0; i < n; i++) {
sum += Math.max(left2right[i], right2left[i]);
}
return sum;
}
// Test cases
console.log(candy([1, 0, 2])); // 5
console.log(candy([1, 2, 2])); // 4
Line Notes
const left2right = new Array(n).fill(1);Initialize left to right candies with 1 candy each
const right2left = new Array(n).fill(1);Initialize right to left candies with 1 candy each
for (let i = 1; i < n; i++)Left to right pass to assign candies based on left neighbor
if (ratings[i] > ratings[i - 1])Check if current rating is higher than left neighbor
left2right[i] = left2right[i - 1] + 1;Assign one more candy than left neighbor
for (let i = n - 2; i >= 0; i--)Right to left pass to assign candies based on right neighbor
if (ratings[i] > ratings[i + 1])Check if current rating is higher than right neighbor
right2left[i] = right2left[i + 1] + 1;Assign one more candy than right neighbor
sum += Math.max(left2right[i], right2left[i]);Take max candies needed from both passes
Two linear passes over the array plus a final linear sum, total O(n) time. Two arrays of size n used for space.
💡 For n=100000, this means about 300000 operations, which is efficient and scalable.
Interview Verdict: Accepted
This is the standard optimal solution for this problem and should be coded in interviews.