1744. Can You Eat Your Favorite Candy on Your Favorite Day
Problem Description
You have different types of candies arranged in order (type 0, type 1, type 2, etc.). The array candiesCount[i]
tells you how many candies of type i
you have.
You play a candy-eating game with these rules:
- You start eating on day 0
- You must eat candies in order by type (you cannot eat any candy of type
i
until you've eaten ALL candies of types 0 throughi-1
) - You must eat at least 1 candy per day
- You can eat multiple types of candy on the same day (as long as you follow the type order rule)
For each query [favoriteType, favoriteDay, dailyCap]
, you want to know: Can you eat at least one candy of favoriteType
on exactly favoriteDay
while never eating more than dailyCap
candies on any single day?
The solution uses prefix sums to track candy positions. For each query:
- Calculate
s
: prefix sum array wheres[i]
= total candies of types 0 throughi-1
- Find the range of candies you could potentially eat by
favoriteDay
:- Minimum: eating 1 candy per day means you'll have eaten
day
candies by then - Maximum: eating
dailyCap
per day means you could eat up to(day + 1) * mx
candies
- Minimum: eating 1 candy per day means you'll have eaten
- Check if this range overlaps with the position of
favoriteType
candies:favoriteType
candies occupy positions froms[t]
tos[t+1] - 1
- You can eat
favoriteType
onfavoriteDay
if your eating range[least, most]
overlaps with candy positions[s[t], s[t+1] - 1]
- This happens when
least < s[t + 1]
andmost > s[t]
Return a boolean array where each element indicates whether the corresponding query is achievable.
Intuition
The key insight is to think about candies as being arranged in a single line, where each candy has a position number. Since we must eat candies in type order, candy type 0 occupies positions 0 to candiesCount[0] - 1
, candy type 1 occupies positions candiesCount[0]
to candiesCount[0] + candiesCount[1] - 1
, and so on.
To determine if we can eat a specific type on a specific day, we need to figure out:
- What range of positions could we have eaten by that day?
- Does this range overlap with the positions of our favorite type?
For the range of positions we could eat by day d
:
- Minimum position: If we eat only 1 candy per day (the minimum required), by day
d
we will have eaten exactlyd
candies (since we start on day 0). So the next candy we eat on dayd
would be at positiond
. - Maximum position: If we eat
dailyCap
candies every day, by the end of dayd
we could have eaten up to(d + 1) * dailyCap
candies total. This means on dayd
, we could potentially be eating candy at position(d + 1) * dailyCap - 1
.
Using prefix sums makes it easy to find where each candy type starts and ends in our imaginary line. If s[i]
represents the total number of candies of types 0 through i-1
, then:
- Candy type
t
starts at positions[t]
- Candy type
t
ends at positions[t + 1] - 1
The final check becomes simple: Can we reach at least the start of our favorite type (s[t]
) but not go past its end (s[t + 1] - 1
)? This translates to checking if our eating range [least, most]
has any overlap with the candy type's range [s[t], s[t + 1] - 1]
. Two ranges overlap when the minimum of one is less than the maximum of the other, which gives us the conditions least < s[t + 1]
and most > s[t]
.
Learn more about Prefix Sum patterns.
Solution Approach
The implementation uses a prefix sum array to efficiently track candy positions and determine if we can eat a specific type on a specific day.
Step 1: Build Prefix Sum Array
s = list(accumulate(candiesCount, initial=0))
We use Python's accumulate
function with initial=0
to create a prefix sum array where:
s[0] = 0
(no candies before type 0)s[1] = candiesCount[0]
(total candies of type 0)s[2] = candiesCount[0] + candiesCount[1]
(total candies of types 0 and 1)- And so on...
This tells us that candy type t
occupies positions from s[t]
to s[t+1] - 1
.
Step 2: Process Each Query
for t, day, mx in queries:
For each query, we extract:
t
: the favorite candy typeday
: the day we want to eat this typemx
: the maximum candies we can eat per day (dailyCap)
Step 3: Calculate Eating Range
least, most = day, (day + 1) * mx
least = day
: The minimum position we could be at on dayday
(eating 1 candy per day, we'd have eatenday
candies by dayday
)most = (day + 1) * mx
: The maximum position we could reach (eatingmx
candies each day forday + 1
days total)
Step 4: Check Range Overlap
ans.append(least < s[t + 1] and most > s[t])
We check if our eating range [least, most)
overlaps with candy type t
's range [s[t], s[t+1])
:
least < s[t + 1]
: We haven't already passed all candies of typet
most > s[t]
: We can reach at least the first candy of typet
Both conditions must be true for us to be able to eat candy type t
on day day
.
Time Complexity: O(n + q)
where n
is the length of candiesCount
and q
is the number of queries. Building the prefix sum takes O(n)
and each query is processed in O(1)
.
Space Complexity: O(n)
for storing the prefix sum array.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example to illustrate the solution approach.
Given:
candiesCount = [5, 2, 6, 4, 1]
queries = [[3, 1, 2], [4, 10, 3], [2, 8, 8]]
Step 1: Build the prefix sum array
First, we create the prefix sum array s
:
s[0] = 0
(no candies before type 0)s[1] = 5
(5 candies of type 0)s[2] = 7
(5 + 2 = 7 candies of types 0-1)s[3] = 13
(5 + 2 + 6 = 13 candies of types 0-2)s[4] = 17
(5 + 2 + 6 + 4 = 17 candies of types 0-3)s[5] = 18
(5 + 2 + 6 + 4 + 1 = 18 total candies)
So s = [0, 5, 7, 13, 17, 18]
This means:
- Type 0 candies are at positions 0-4
- Type 1 candies are at positions 5-6
- Type 2 candies are at positions 7-12
- Type 3 candies are at positions 13-16
- Type 4 candies are at position 17
Step 2: Process each query
Query 1: [3, 1, 2]
- Can we eat type 3 on day 1 with dailyCap = 2?
- Calculate eating range:
least = 1
(minimum position on day 1)most = (1 + 1) * 2 = 4
(maximum position we could reach)
- Type 3 candies are at positions 13-16 (
s[3] = 13
tos[4] - 1 = 16
) - Check overlap:
least < s[4]
? →1 < 17
✓ ANDmost > s[3]
? →4 > 13
✗ - Result: False (we can't reach position 13 by day 1)
Query 2: [4, 10, 3]
- Can we eat type 4 on day 10 with dailyCap = 3?
- Calculate eating range:
least = 10
(minimum position on day 10)most = (10 + 1) * 3 = 33
(maximum position we could reach)
- Type 4 candies are at position 17 (
s[4] = 17
tos[5] - 1 = 17
) - Check overlap:
least < s[5]
? →10 < 18
✓ ANDmost > s[4]
? →33 > 17
✓ - Result: True (we can reach position 17 on day 10)
Query 3: [2, 8, 8]
- Can we eat type 2 on day 8 with dailyCap = 8?
- Calculate eating range:
least = 8
(minimum position on day 8)most = (8 + 1) * 8 = 72
(maximum position we could reach)
- Type 2 candies are at positions 7-12 (
s[2] = 7
tos[3] - 1 = 12
) - Check overlap:
least < s[3]
? →8 < 13
✓ ANDmost > s[2]
? →72 > 7
✓ - Result: True (positions 8-12 are within our reach on day 8)
Final Answer: [False, True, True]
Solution Implementation
1class Solution:
2 def canEat(self, candiesCount: List[int], queries: List[List[int]]) -> List[bool]:
3 from itertools import accumulate
4 from typing import List
5
6 # Calculate prefix sum of candies (cumulative sum)
7 # prefix_sum[i] represents total candies from type 0 to type i-1
8 prefix_sum = list(accumulate(candiesCount, initial=0))
9
10 result = []
11
12 for favorite_type, favorite_day, daily_cap in queries:
13 # Minimum candies eaten: eat 1 candy per day until favorite_day
14 min_candies_eaten = favorite_day
15
16 # Maximum candies eaten: eat daily_cap candies per day through favorite_day
17 max_candies_eaten = (favorite_day + 1) * daily_cap
18
19 # Check if we can eat favorite_type candy on favorite_day
20 # We need to have eaten enough to reach favorite_type candies (> prefix_sum[favorite_type])
21 # But not so many that we've already consumed all of them (< prefix_sum[favorite_type + 1])
22 can_eat_favorite = (min_candies_eaten < prefix_sum[favorite_type + 1] and
23 max_candies_eaten > prefix_sum[favorite_type])
24
25 result.append(can_eat_favorite)
26
27 return result
28
1class Solution {
2 public boolean[] canEat(int[] candiesCount, int[][] queries) {
3 // Get the number of candy types
4 int numCandyTypes = candiesCount.length;
5
6 // Build prefix sum array to store cumulative candy counts
7 // prefixSum[i] represents total candies from type 0 to type i-1
8 long[] prefixSum = new long[numCandyTypes + 1];
9 for (int i = 0; i < numCandyTypes; i++) {
10 prefixSum[i + 1] = prefixSum[i] + candiesCount[i];
11 }
12
13 // Process each query
14 int numQueries = queries.length;
15 boolean[] result = new boolean[numQueries];
16
17 for (int i = 0; i < numQueries; i++) {
18 // Extract query parameters
19 int favoriteType = queries[i][0];
20 int favoriteDay = queries[i][1];
21 int dailyCap = queries[i][2];
22
23 // Calculate the range of candies that can be eaten
24 // Minimum: eat 1 candy per day, so by favoriteDay we eat at least favoriteDay candies
25 long minCandiesEaten = favoriteDay;
26
27 // Maximum: eat dailyCap candies per day for (favoriteDay + 1) days
28 // +1 because days are 0-indexed, so day 0 means 1 day
29 long maxCandiesEaten = (long)(favoriteDay + 1) * dailyCap;
30
31 // Check if we can reach favorite type candy
32 // We can eat favorite type if:
33 // 1. minCandiesEaten < total candies up to and including favoriteType
34 // 2. maxCandiesEaten > total candies before favoriteType
35 result[i] = minCandiesEaten < prefixSum[favoriteType + 1] &&
36 maxCandiesEaten > prefixSum[favoriteType];
37 }
38
39 return result;
40 }
41}
42
1using ll = long long;
2
3class Solution {
4public:
5 vector<bool> canEat(vector<int>& candiesCount, vector<vector<int>>& queries) {
6 int n = candiesCount.size();
7
8 // Build prefix sum array to store cumulative candy counts
9 // prefixSum[i] represents total candies from type 0 to type i-1
10 vector<ll> prefixSum(n + 1);
11 for (int i = 0; i < n; ++i) {
12 prefixSum[i + 1] = prefixSum[i] + candiesCount[i];
13 }
14
15 vector<bool> result;
16
17 // Process each query
18 for (auto& query : queries) {
19 int favoriteType = query[0];
20 int favoriteDay = query[1];
21 int dailyCap = query[2];
22
23 // Calculate the range of candies we can eat
24 // Minimum: eat 1 candy per day, need to eat at least 'favoriteDay' candies before reaching favorite type
25 ll minCandiesEaten = favoriteDay;
26
27 // Maximum: eat 'dailyCap' candies per day for (favoriteDay + 1) days
28 ll maxCandiesEaten = 1ll * (favoriteDay + 1) * dailyCap;
29
30 // Check if we can eat favorite type candy on the given day
31 // We can eat it if:
32 // 1. We haven't eaten all candies of favorite type yet (minCandiesEaten < total candies up to and including favorite type)
33 // 2. We have eaten enough to reach favorite type (maxCandiesEaten > total candies before favorite type)
34 bool canEatFavorite = (minCandiesEaten < prefixSum[favoriteType + 1]) &&
35 (maxCandiesEaten > prefixSum[favoriteType]);
36
37 result.emplace_back(canEatFavorite);
38 }
39
40 return result;
41 }
42};
43
1type ll = number;
2
3function canEat(candiesCount: number[], queries: number[][]): boolean[] {
4 const n: number = candiesCount.length;
5
6 // Build prefix sum array to store cumulative candy counts
7 // prefixSum[i] represents total candies from type 0 to type i-1
8 const prefixSum: ll[] = new Array(n + 1).fill(0);
9 for (let i = 0; i < n; i++) {
10 prefixSum[i + 1] = prefixSum[i] + candiesCount[i];
11 }
12
13 const result: boolean[] = [];
14
15 // Process each query
16 for (const query of queries) {
17 const favoriteType: number = query[0];
18 const favoriteDay: number = query[1];
19 const dailyCap: number = query[2];
20
21 // Calculate the range of candies we can eat
22 // Minimum: eat 1 candy per day, need to eat at least 'favoriteDay' candies before reaching favorite type
23 const minCandiesEaten: ll = favoriteDay;
24
25 // Maximum: eat 'dailyCap' candies per day for (favoriteDay + 1) days
26 const maxCandiesEaten: ll = (favoriteDay + 1) * dailyCap;
27
28 // Check if we can eat favorite type candy on the given day
29 // We can eat it if:
30 // 1. We haven't eaten all candies of favorite type yet (minCandiesEaten < total candies up to and including favorite type)
31 // 2. We have eaten enough to reach favorite type (maxCandiesEaten > total candies before favorite type)
32 const canEatFavorite: boolean = (minCandiesEaten < prefixSum[favoriteType + 1]) &&
33 (maxCandiesEaten > prefixSum[favoriteType]);
34
35 result.push(canEatFavorite);
36 }
37
38 return result;
39}
40
Time and Space Complexity
Time Complexity: O(n + q)
where n
is the length of candiesCount
and q
is the length of queries
.
- Computing the prefix sum using
accumulate()
takesO(n)
time to iterate through all elements incandiesCount
. - Processing each query takes
O(1)
time as we're only performing constant-time operations (arithmetic calculations and array indexing). - Since we process
q
queries, the query processing takesO(q)
time in total. - Overall time complexity:
O(n) + O(q) = O(n + q)
.
Space Complexity: O(n)
where n
is the length of candiesCount
.
- The prefix sum array
s
storesn + 1
elements (including the initial 0), requiringO(n)
space. - The answer list
ans
storesq
boolean values, but this is considered part of the output and typically not counted in auxiliary space complexity. - Variables
least
,most
,t
,day
, andmx
useO(1)
space. - Overall auxiliary space complexity:
O(n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Off-by-One Error in Day Calculation
Pitfall: A common mistake is confusing the day indexing. Since we start eating on day 0, by day d
we have had d + 1
days to eat candies. Many developers incorrectly calculate the maximum candies eaten as day * dailyCap
instead of (day + 1) * dailyCap
.
Wrong Implementation:
max_candies_eaten = day * daily_cap # WRONG! Misses one day
Correct Implementation:
max_candies_eaten = (day + 1) * daily_cap # Correct: includes day 0 through day d
2. Incorrect Range Overlap Logic
Pitfall: When checking if two ranges overlap, developers often use incorrect comparison operators or apply wrong logic. The ranges are [min_eaten, max_eaten)
and [prefix_sum[t], prefix_sum[t+1])
.
Wrong Implementation:
# Using <= and >= incorrectly can_eat = min_candies_eaten <= prefix_sum[favorite_type + 1] and max_candies_eaten >= prefix_sum[favorite_type]
Correct Implementation:
# Proper range overlap: first range hasn't passed second AND can reach second can_eat = min_candies_eaten < prefix_sum[favorite_type + 1] and max_candies_eaten > prefix_sum[favorite_type]
3. Forgetting Edge Case of Eating 1 Candy Per Day
Pitfall: Some developers calculate the minimum position incorrectly by assuming we must eat at least one candy on the favorite day itself, using day + 1
as the minimum.
Wrong Implementation:
min_candies_eaten = day + 1 # WRONG! This assumes we've eaten day+1 candies by day d
Correct Implementation:
min_candies_eaten = day # Correct: eating 1 per day, we've eaten exactly 'day' candies by day 'day'
4. Integer Overflow in Maximum Calculation
Pitfall: For large values of favorite_day
and daily_cap
, the multiplication (day + 1) * daily_cap
might overflow in languages with fixed integer sizes. While Python handles arbitrary precision integers, this is a concern in languages like Java or C++.
Solution for Other Languages:
# In Python, this is handled automatically max_candies_eaten = (favorite_day + 1) * daily_cap # In Java/C++, use long/long long: # long maxCandiesEaten = (long)(favoriteDay + 1) * dailyCap;
5. Misunderstanding Candy Position Indexing
Pitfall: Confusing 0-based candy positions with 1-based counting. The first candy (position 0) is eaten on day 0 when we've eaten 0 candies previously.
Example to Remember:
- Day 0: Can eat candies at positions [0, dailyCap)
- Day 1: Can eat candies at positions [1, 2*dailyCap)
- Day d: Can eat candies at positions [d, (d+1)*dailyCap)
The minimum position on day d
is d
(eating 1 per day), not d+1
.
Which data structure is used to implement recursion?
Recommended Readings
Prefix Sum The prefix sum is an incredibly powerful and straightforward technique Its primary goal is to allow for constant time range sum queries on an array What is Prefix Sum The prefix sum of an array at index i is the sum of all numbers from index 0 to i By
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!