LeetCode 1744 - Can You Eat Your Favorite Candy on Your Favorite Day?
The problem gives us an array candiesCount where candiesCount[i] represents how many candies exist for candy type i.
Difficulty: 🟡 Medium
Topics: Array, Prefix Sum
Solution
Problem Understanding
The problem gives us an array candiesCount where candiesCount[i] represents how many candies exist for candy type i. Candy types must be eaten in order, which means you cannot eat any candy of type i until every candy from all previous types 0 through i - 1 has already been eaten.
You are also given multiple queries. Each query contains:
favoriteTypefavoriteDaydailyCap
For each query, we must determine whether it is possible to eat at least one candy of type favoriteType on day favoriteDay, while following all rules:
- You start eating on day
0. - You must eat at least one candy every day.
- You cannot eat more than
dailyCapcandies on any day. - Candy types must be consumed in order.
The output is a boolean array where each position corresponds to one query.
The constraints are large:
- Up to
10^5candy types - Up to
10^5queries - Day values and caps can be as large as
10^9
These constraints immediately tell us that simulating day by day is impossible. We need a mathematical or prefix-sum based solution.
An important observation is that for a given day:
- There is a minimum number of candies you must have eaten by then
- There is a maximum number of candies you could have eaten by then
We can treat each query as a range overlap problem.
Several edge cases are important:
- A query may ask about day
0 dailyCapmay be extremely large- The favorite candy type may be the first or last type
- Prefix sums can become very large, so 64-bit integers are required
- A candy type may become unreachable because earlier candy types consume too many days
Approaches
Brute Force Approach
A brute-force solution would attempt to simulate candy consumption for every query.
For each query:
- Simulate eating candies day by day
- Respect the maximum daily cap
- Track which candy type is currently available
- Check whether the target candy type can be eaten on the target day
This approach is conceptually correct because it directly follows the rules of the problem. However, it becomes infeasible very quickly.
The value of favoriteDay can reach 10^9, which makes day-by-day simulation impossible. Even simulating greedily would still be far too slow for 10^5 queries.
Key Insight for the Optimal Solution
Instead of simulating consumption, we can reason about ranges.
Suppose we are answering a query:
favoriteType = tfavoriteDay = ddailyCap = c
By day d:
- The minimum number of candies eaten is
d + 1, because you must eat at least one candy per day. - The maximum number of candies eaten is
(d + 1) * c.
Now consider candy type t.
Let:
prefix[t]= total candies from types0throughtprefix[t - 1]= total candies before typet
Then:
- The first candy of type
tis candy numberprefix[t - 1] + 1 - The last candy of type
tis candy numberprefix[t]
To eat a candy of type t on day d, the range of candies eaten by day d must overlap with the range occupied by type t.
This becomes an interval overlap problem.
The query is possible if:
maximum candies eaten by day d >= first candy of type t
AND
minimum candies eaten by day d <= last candy of type t
Or equivalently:
(d + 1) * c > prefix[t - 1]
AND
(d + 1) <= prefix[t]
This transforms the problem into efficient prefix sum lookups.
Approach Comparison
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(Q × D) | O(1) | Simulates candy consumption day by day |
| Optimal | O(N + Q) | O(N) | Uses prefix sums and interval overlap logic |
Where:
N = len(candiesCount)Q = len(queries)Dcan be as large as10^9
Algorithm Walkthrough
- Build a prefix sum array.
The prefix sum array stores the cumulative number of candies up to each type.
prefix[i] = candiesCount[0] + candiesCount[1] + ... + candiesCount[i]
This allows us to quickly determine:
- How many candies exist before a type
- The total candies up to a type
- Process each query independently.
For a query [favoriteType, favoriteDay, dailyCap]:
- Let:
t = favoriteType
d = favoriteDay
c = dailyCap
- Compute the minimum candies eaten by day
d.
Since at least one candy must be eaten each day:
minEaten = d + 1
- Compute the maximum candies eaten by day
d.
Since at most c candies can be eaten each day:
maxEaten = (d + 1) * c
- Compute the candy range for type
t.
The candies belonging to type t occupy:
firstCandy = prefix[t - 1] + 1
lastCandy = prefix[t]
If t == 0, then:
firstCandy = 1
- Check whether the ranges overlap.
We can eat type t on day d if:
maxEaten >= firstCandy
AND
minEaten <= lastCandy
- Store the boolean result.
Repeat this process for all queries.
Why it works
The algorithm works because every valid eating schedule produces a total number of candies eaten by day d that lies between:
[d + 1, (d + 1) * dailyCap]
Candy type t occupies a fixed interval in the global candy ordering:
[firstCandy, lastCandy]
If these intervals overlap, then there exists some valid number of candies eaten by day d that lands within the range for type t. Therefore, eating type t on day d is possible.
If the intervals do not overlap, then no valid eating schedule can reach type t on that day.
Python Solution
from typing import List
class Solution:
def canEat(self, candiesCount: List[int], queries: List[List[int]]) -> List[bool]:
n = len(candiesCount)
# Build prefix sums
prefix = [0] * n
prefix[0] = candiesCount[0]
for i in range(1, n):
prefix[i] = prefix[i - 1] + candiesCount[i]
answer = []
for favoriteType, favoriteDay, dailyCap in queries:
min_eaten = favoriteDay + 1
max_eaten = (favoriteDay + 1) * dailyCap
candies_before = prefix[favoriteType - 1] if favoriteType > 0 else 0
candies_up_to = prefix[favoriteType]
can_eat = (
max_eaten > candies_before and
min_eaten <= candies_up_to
)
answer.append(can_eat)
return answer
The implementation begins by constructing a prefix sum array. This array allows constant-time lookup of how many candies exist before a specific type and how many candies exist up to that type.
For each query, the code computes:
- The minimum possible candies eaten by the target day
- The maximum possible candies eaten by the target day
It then determines the interval occupied by the favorite candy type.
The condition:
max_eaten > candies_before
ensures that we can reach the target type by that day.
The condition:
min_eaten <= candies_up_to
ensures that we have not already exhausted the target type before that day.
If both conditions hold, the intervals overlap and the answer is True.
Go Solution
func canEat(candiesCount []int, queries [][]int) []bool {
n := len(candiesCount)
// Build prefix sums using int64 to avoid overflow
prefix := make([]int64, n)
prefix[0] = int64(candiesCount[0])
for i := 1; i < n; i++ {
prefix[i] = prefix[i-1] + int64(candiesCount[i])
}
answer := make([]bool, len(queries))
for i, query := range queries {
favoriteType := query[0]
favoriteDay := int64(query[1])
dailyCap := int64(query[2])
minEaten := favoriteDay + 1
maxEaten := (favoriteDay + 1) * dailyCap
var candiesBefore int64 = 0
if favoriteType > 0 {
candiesBefore = prefix[favoriteType-1]
}
candiesUpTo := prefix[favoriteType]
canEatCandy := (
maxEaten > candiesBefore &&
minEaten <= candiesUpTo
)
answer[i] = canEatCandy
}
return answer
}
The Go implementation follows the same logic as the Python solution. The main difference is that Go requires explicit handling of integer overflow.
Since values can exceed 32-bit integer limits:
(10^9 + 1) * 10^9
all prefix sums and arithmetic involving days or caps use int64.
Slices are used naturally for prefix sums and results. No special handling for nil slices is necessary because the constraints guarantee valid input sizes.
Worked Examples
Example 1
candiesCount = [7,4,5,3,8]
queries = [[0,2,2],[4,2,4],[2,13,1000000000]]
Step 1: Build Prefix Sum
| Type | Candies | Prefix Sum |
|---|---|---|
| 0 | 7 | 7 |
| 1 | 4 | 11 |
| 2 | 5 | 16 |
| 3 | 3 | 19 |
| 4 | 8 | 27 |
Query 1: [0,2,2]
| Variable | Value |
|---|---|
| favoriteType | 0 |
| favoriteDay | 2 |
| dailyCap | 2 |
| minEaten | 3 |
| maxEaten | 6 |
| candiesBefore | 0 |
| candiesUpTo | 7 |
Check conditions:
6 > 0 -> true
3 <= 7 -> true
Answer: true
Query 2: [4,2,4]
| Variable | Value |
|---|---|
| favoriteType | 4 |
| favoriteDay | 2 |
| dailyCap | 4 |
| minEaten | 3 |
| maxEaten | 12 |
| candiesBefore | 19 |
| candiesUpTo | 27 |
Check conditions:
12 > 19 -> false
3 <= 27 -> true
Answer: false
We cannot reach type 4 by day 2.
Query 3: [2,13,1000000000]
| Variable | Value |
|---|---|
| favoriteType | 2 |
| favoriteDay | 13 |
| dailyCap | 1000000000 |
| minEaten | 14 |
| maxEaten | 14000000000 |
| candiesBefore | 11 |
| candiesUpTo | 16 |
Check conditions:
14000000000 > 11 -> true
14 <= 16 -> true
Answer: true
Example 2
candiesCount = [5,2,6,4,1]
queries = [[3,1,2],[4,10,3],[3,10,100],[4,100,30],[1,3,1]]
Prefix Sum
| Type | Candies | Prefix Sum |
|---|---|---|
| 0 | 5 | 5 |
| 1 | 2 | 7 |
| 2 | 6 | 13 |
| 3 | 4 | 17 |
| 4 | 1 | 18 |
Query Analysis
| Query | minEaten | maxEaten | candiesBefore | candiesUpTo | Result |
|---|---|---|---|---|---|
| [3,1,2] | 2 | 4 | 13 | 17 | false |
| [4,10,3] | 11 | 33 | 17 | 18 | true |
| [3,10,100] | 11 | 1100 | 13 | 17 | true |
| [4,100,30] | 101 | 3030 | 17 | 18 | false |
| [1,3,1] | 4 | 4 | 5 | 7 | false |
Final output:
[false,true,true,false,false]
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(N + Q) | One pass to build prefix sums and one pass through queries |
| Space | O(N) | Prefix sum array requires linear extra space |
The prefix sum array is built once in linear time. Each query is then answered in constant time using arithmetic and prefix lookups. This is efficient enough for the problem constraints of 10^5 elements and queries.
Test Cases
from typing import List
class Solution:
def canEat(self, candiesCount: List[int], queries: List[List[int]]) -> List[bool]:
n = len(candiesCount)
prefix = [0] * n
prefix[0] = candiesCount[0]
for i in range(1, n):
prefix[i] = prefix[i - 1] + candiesCount[i]
answer = []
for favoriteType, favoriteDay, dailyCap in queries:
min_eaten = favoriteDay + 1
max_eaten = (favoriteDay + 1) * dailyCap
candies_before = prefix[favoriteType - 1] if favoriteType > 0 else 0
candies_up_to = prefix[favoriteType]
answer.append(
max_eaten > candies_before and
min_eaten <= candies_up_to
)
return answer
sol = Solution()
# Provided example 1
assert sol.canEat(
[7,4,5,3,8],
[[0,2,2],[4,2,4],[2,13,1000000000]]
) == [True, False, True]
# Provided example 2
assert sol.canEat(
[5,2,6,4,1],
[[3,1,2],[4,10,3],[3,10,100],[4,100,30],[1,3,1]]
) == [False, True, True, False, False]
# Single candy type, day 0 reachable
assert sol.canEat(
[10],
[[0,0,1]]
) == [True] # can eat first candy immediately
# Cannot reach later type soon enough
assert sol.canEat(
[100,100],
[[1,0,1]]
) == [False] # must finish type 0 first
# Large daily cap allows reaching quickly
assert sol.canEat(
[1,1,1],
[[2,0,100]]
) == [False] # still cannot skip earlier types on day 0
# Exact boundary overlap
assert sol.canEat(
[5],
[[0,4,1]]
) == [True] # fifth candy eaten on day 4
# Already exhausted target type
assert sol.canEat(
[2],
[[0,5,1]]
) == [False] # type 0 exhausted before day 5
# Large values stress test
assert sol.canEat(
[100000] * 100000,
[[99999, 10**9, 10**9]]
) == [False]
# Multiple mixed queries
assert sol.canEat(
[3,5,2],
[[0,1,2],[1,2,2],[2,4,1]]
) == [True, True, False]
Test Case Summary
| Test | Why |
|---|---|
| Example 1 | Validates standard mixed outcomes |
| Example 2 | Tests multiple query combinations |
| Single candy type | Simplest possible input |
| Cannot reach later type | Ensures ordering rule is enforced |
| Large daily cap | Verifies cap does not bypass ordering |
| Exact boundary overlap | Tests interval boundary correctness |
| Exhausted target type | Ensures late days fail properly |
| Large values stress test | Verifies performance and overflow safety |
| Mixed queries | Tests varied scenarios together |
Edge Cases
Day Zero Queries
Queries with favoriteDay = 0 are easy to mishandle because only one day of eating has occurred. The implementation correctly computes:
minEaten = 1
maxEaten = dailyCap
This ensures the logic still works for the very first day.
Extremely Large Daily Caps
The value of dailyCap can reach 10^9, and multiplying it by (favoriteDay + 1) can exceed 32-bit integer limits. A naive implementation using regular integers in some languages would overflow.
The Go solution uses int64, and Python naturally supports arbitrary precision integers.
Favorite Type Already Exhausted
A subtle case occurs when the minimum candies eaten by day d already exceeds the last candy index of the target type.
For example:
candiesCount = [2]
query = [0,5,1]
By day 5, at least 6 candies must have been eaten, but only 2 candies of type 0 exist.
The condition:
minEaten <= candiesUpTo
correctly detects this and returns False.
Large Numbers of Queries
Since both candiesCount and queries can contain 10^5 elements, any per-query linear scan would time out.
The prefix sum approach guarantees constant-time query evaluation after preprocessing, making the solution scalable enough for the constraints.