Given an array arr[] where each element represents the rating of a child, find the minimum number of candies required to distribute among all children under the following conditions:
- Every child must receive at least one candy.
- A child with a higher rating than their immediate neighbor(s) must receive more candies than that neighbor.
Examples:
Input: arr[] = [1, 2, 3, 4, 5]
Output: 15
Explanation: According to the rule, if a child’s rating is greater than the neighbor, he must get more candy than the neighbor.
Child 0 → rating 1 → gets 1 candy
Child 1 → rating 2 → greater than 1 → gets 2 candies
Child 2 → rating 3 → greater than 2 → gets 3 candies
Child 3 → rating 4 → greater than 3 → gets 4 candies
Child 4 → rating 5 → greater than 4 → gets 5 candies
Total candies are 1 + 2 + 3 + 4 + 5 = 15.Input: arr[] = [9, 9, 9, 9]
Output: 4
Explanation: No child has a strictly greater rating than the neighbor. So, each child only needs the minimum 1 candy.
Table of Content
[Approach 1] Greedy Approach with Dual Traversal - O(n) Time and O(n) Space
We need to ensure each student has more candies than both of their neighbors if their score is higher.
To handle the left neighbor, we traverse left → right: if a student’s score is higher than the one on the left, give them more candies.
To handle the right neighbor, we traverse right → left: if a student’s score is higher than the one on the right, give them more candies.
Finally, for each student we take the sum of maximum from both passes.
Why does taking the maximum work?
Every student must satisfy both neighbors:
- The left-to-right pass ensures fairness with the left neighbor (if a student has a higher score, they get more candies).
- The right-to-left pass ensures fairness with the right neighbor.
But a student might need more candies to satisfy one side than the other. To keep the rule valid in both directions at once, we give them the maximum of the two counts. This way, no student violates the rule with either neighbor, while still keeping the distribution minimal.
#include <iostream>
#include <vector>
using namespace std;
int minCandy(vector<int> &arr) {
int n = arr.size();
vector<int> leftcandy(n, 1);
vector<int> rightcandy(n, 1);
// left pass
for (int i = 1; i < n; i++) {
if (arr[i] > arr[i - 1])
leftcandy[i] = leftcandy[i - 1] + 1;
}
// right pass
for (int i = n - 2; i >= 0; i--){
if (arr[i] > arr[i + 1])
rightcandy[i] = rightcandy[i + 1] + 1;
}
// Calculate final answer
int ans = 0;
for (int i = 0; i < n; i++) {
// Take max at each position
ans += max(leftcandy[i], rightcandy[i]);
}
return ans;
}
int main() {
vector<int> arr = {1,2,3,4,5};
cout << minCandy(arr);
}
import java.util.Arrays;
public class GfG {
public static int minCandy(int[] arr) {
int n = arr.length;
int[] leftCandy = new int[n];
int[] rightCandy = new int[n];
Arrays.fill(leftCandy, 1);
Arrays.fill(rightCandy, 1);
// Left pass
for (int i = 1; i < n; i++) {
if (arr[i] > arr[i - 1])
leftCandy[i] = leftCandy[i - 1] + 1;
}
// Right pass
for (int i = n - 2; i >= 0; i--) {
if (arr[i] > arr[i + 1])
rightCandy[i] = rightCandy[i + 1] + 1;
}
// Calculate final answer
int ans = 0;
for (int i = 0; i < n; i++) {
// Take max at each position
ans += Math.max(leftCandy[i], rightCandy[i]);
}
return ans;
}
public static void main(String[] args)
{
int[] arr = { 1, 2, 3, 4, 5 };
System.out.println(minCandy(arr));
}
}
import array
def minCandy(arr):
n = len(arr)
leftcandy = array.array('i', [1] * n)
rightcandy = array.array('i', [1] * n)
# left pass
for i in range(1, n):
if arr[i] > arr[i - 1]:
leftcandy[i] = leftcandy[i - 1] + 1
# right pass
for i in range(n - 2, -1, -1):
if arr[i] > arr[i + 1]:
rightcandy[i] = rightcandy[i + 1] + 1
# calculate final answer
return sum(max(leftcandy[i], rightcandy[i]) for i in range(n))
if __name__ == "__main__":
arr = array.array('i', [1, 2, 3, 4, 5 ])
print(minCandy(arr))
using System;
class GfG {
static int minCandy(int[] arr) {
int n = arr.Length;
int[] leftCandy = new int[n];
int[] rightCandy = new int[n];
Array.Fill(leftCandy, 1);
Array.Fill(rightCandy, 1);
// Left pass
for (int i = 1; i < n; i++) {
if (arr[i] > arr[i - 1])
leftCandy[i] = leftCandy[i - 1] + 1;
}
// Right pass
for (int i = n - 2; i >= 0; i--) {
if (arr[i] > arr[i + 1])
rightCandy[i] = rightCandy[i + 1] + 1;
}
// Calculate final answer
int ans = 0;
for (int i = 0; i < n; i++) {
ans += Math.Max(leftCandy[i], rightCandy[i]);
}
return ans;
}
static void Main() {
int[] arr = {1, 2, 3, 4, 5 };
Console.WriteLine(minCandy(arr));
}
}
function minCandy(arr) {
let n = arr.length;
let leftCandy = new Array(n).fill(1);
let rightCandy = new Array(n).fill(1);
// Left pass
for (let i = 1; i < n; i++) {
if (arr[i] > arr[i - 1]) {
leftCandy[i] = leftCandy[i - 1] + 1;
}
}
// Right pass
for (let i = n - 2; i >= 0; i--) {
if (arr[i] > arr[i + 1]) {
rightCandy[i] = rightCandy[i + 1] + 1;
}
}
// Calculate final answer
let ans = 0;
for (let i = 0; i < n; i++) {
ans += Math.max(leftCandy[i], rightCandy[i]);
}
return ans;
}
// Driver code
let arr = [1, 2, 3, 4, 5 ];
console.log(minCandy(arr));
Output
15
[Approach 2] Greedy Approach Using Rising and Falling Slopes - O(n) Time and O(1) Space
The key idea is that every valid candy distribution forms slopes of increasing and decreasing ratings.
On an increasing slope, each child must get 1 more candy than the previous one. This ensures all local rising conditions are satisfied.
On a decreasing slope, the same logic applies in reverse, so each child gets 1 more than the next.
At a peak, both conditions apply. By subtracting the smaller overlap, we avoid double-counting but still guarantee the peak has more candies than both neighbors.
Steps to solve the problem:
- Start by giving each child 1 candy (hence total = n).
- Move from left to right, comparing the current rating with the previous one.
- If two adjacent children have the same rating, just move forward (no extra candy is needed).
- While the current rating is higher than the previous one, keep increasing candies for each child (peak++) and add to total.(Increasing sequence).
- While the current rating is lower than the previous one, keep decreasing (valley++) and add to total (decreasing sequence).
- The peak child is counted in both increasing and decreasing sequences, so subtract min(peak, valley) to remove the extra candy.
- Repeat the process until all children are covered.
#include <iostream>
#include <vector>
using namespace std;
int minCandy(vector<int> &arr) {
int n = arr.size();
// create variable to store count
// of candies, initlize it with n
int total = n;
int i = 1;
// Traverse from left to right
while (i < n) {
// if rating of ith children is
// equal to the previous children
if (arr[i] == arr[i - 1]) {
i++;
continue;
}
// to find the increasing sequence
int peak = 0;
while (i < n && arr[i] > arr[i - 1]) {
peak++;
total += peak;
i++;
}
if (i == n) {
return total;
}
// to find the decreasing sequence
int valley = 0;
while (i < n && arr[i] < arr[i - 1]) {
valley++;
total += valley;
i++;
}
// remove the extra candy added twice
total -= min(peak, valley);
}
return total;
}
int main() {
vector<int> arr = {1, 2, 3, 4, 5 };
cout << minCandy(arr);
return 0;
}
class GfG {
static int minCandy(int[] arr) {
int n = arr.length;
// create variable to store count
// of candies, initialize it with n
int total = n;
int i = 1;
// Traverse from left to right
while (i < n) {
// if rating of ith children is
// equal to the previous children
if (arr[i] == arr[i - 1]) {
i++;
continue;
}
// to find the increasing sequence
int peak = 0;
while (i < n && arr[i] > arr[i - 1]) {
peak++;
total += peak;
i++;
}
if (i == n) {
return total;
}
// to find the decreasing sequence
int valley = 0;
while (i < n && arr[i] < arr[i - 1]) {
valley++;
total += valley;
i++;
}
// remove the extra candy added twice
total -= Math.min(peak, valley);
}
return total;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5 };
System.out.println(minCandy(arr));
}
}
def minCandy(arr):
n = len(arr)
# create variable to store count
# of candies, initialize it with n
total = n
i = 1
# Traverse from left to right
while i < n:
# if rating of ith children is
# equal to the previous children
if arr[i] == arr[i - 1]:
i += 1
continue
# to find the increasing sequence
peak = 0
while i < n and arr[i] > arr[i - 1]:
peak += 1
total += peak
i += 1
if i == n:
return total
# to find the decreasing sequence
valley = 0
while i < n and arr[i] < arr[i - 1]:
valley += 1
total += valley
i += 1
# remove the extra candy added twice
total -= min(peak, valley)
return total
if __name__ == "__main__":
arr = [1, 2, 3, 4, 5 ]
print(minCandy(arr))
using System;
class GfG {
static int minCandy(int[] arr) {
int n = arr.Length;
// create variable to store count
// of candies, initialize it with n
int total = n;
int i = 1;
// Traverse from left to right
while (i < n) {
// if rating of ith children is
// equal to the previous children
if (arr[i] == arr[i - 1]) {
i++;
continue;
}
// to find the increasing sequence
int peak = 0;
while (i < n && arr[i] > arr[i - 1]) {
peak++;
total += peak;
i++;
}
if (i == n) {
return total;
}
// to find the decreasing sequence
int valley = 0;
while (i < n && arr[i] < arr[i - 1]) {
valley++;
total += valley;
i++;
}
// remove the extra candy added twice
total -= Math.Min(peak, valley);
}
return total;
}
public static void Main() {
int[] arr = {1, 2, 3, 4, 5 };
Console.WriteLine(minCandy(arr));
}
}
function minCandy(arr) {
const n = arr.length;
// create variable to store count
// of candies, initialize it with n
let total = n;
let i = 1;
// Traverse from left to right
while (i < n) {
// if rating of ith children is
// equal to the previous children
if (arr[i] === arr[i - 1]) {
i++;
continue;
}
// to find the increasing sequence
let peak = 0;
while (i < n && arr[i] > arr[i - 1]) {
peak++;
total += peak;
i++;
}
if (i === n) {
return total;
}
// to find the decreasing sequence
let valley = 0;
while (i < n && arr[i] < arr[i - 1]) {
valley++;
total += valley;
i++;
}
// remove the extra candy added twice
total -= Math.min(peak, valley);
}
return total;
}
// Driver Code
const arr = [1, 2, 3, 4, 5 ];
console.log(minCandy(arr));
Output
15