Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1744. Can You Eat Your Favorite Candy on Your Favorite Day? - Leetcode Solution

Problem Description

You are given an array candiesCount where candiesCount[i] represents the number of candies of the ith type. You are also given a 2D array queries, where each query is of the form [favoriteType, favoriteDay, dailyCap]:

  • favoriteType: The type of candy you like (0-indexed).
  • favoriteDay: The day (0-indexed) you want to eat your favorite candy.
  • dailyCap: The maximum number of candies you can eat each day.

Starting from day 0, you eat at least one candy per day and at most dailyCap candies per day. You must eat all candies of type 0 before eating type 1, all candies of type 1 before type 2, and so on (i.e., you eat candies in order of type).

For each query, determine if it is possible to eat a candy of your favoriteType on your favoriteDay given the constraints above. Return an array of boolean values, one for each query.

Key constraints:

  • You must eat at least one candy per day.
  • You cannot skip any candy type.
  • You may not eat more than dailyCap candies per day.
  • Each query is independent.

Thought Process

To solve this problem, let's first think about what it means to eat a candy of a specific type on a specific day. Since you must eat candies in order, you can only eat type i after finishing all candies of types before i. For any day, you can eat between 1 and dailyCap candies per day, so the total number of candies you could have eaten by day favoriteDay is between favoriteDay + 1 (if you eat 1 per day) and (favoriteDay + 1) * dailyCap (if you eat the max each day).

The brute-force approach would simulate eating candies day by day, but this would be too slow for large inputs. Instead, we can use prefix sums to quickly calculate how many candies are before your favorite type and how many candies you need to eat to start and finish that type.

The key insight is to check if there is any overlap between the range of candies you could have eaten by favoriteDay and the range of candies corresponding to your favorite type.

Solution Approach

Let's break down the solution step-by-step:

  1. Compute Prefix Sums:
    • We use a prefix sum array so that prefix[i] is the total number of candies of types 0 to i-1.
    • This allows us to quickly know how many candies you must eat before starting type i.
  2. For Each Query:
    • Let favoriteType = t, favoriteDay = d, dailyCap = cap.
    • The range of candies you could have eaten by day d is [d + 1, (d + 1) * cap].
    • The range of candies of type t is [prefix[t] + 1, prefix[t] + candiesCount[t]].
    • To be able to eat your favorite candy on day d, these two ranges must overlap.
  3. Check for Overlap:
    • Two intervals [a1, a2] and [b1, b2] overlap if max(a1, b1) <= min(a2, b2).
    • If they overlap, return True for this query; else, False.

This approach is efficient because prefix sums allow constant-time range queries, and we avoid simulating each day.

Example Walkthrough

Consider the following input:

  • candiesCount = [7, 4, 5, 3, 8]
  • queries = [[0,2,2], [4,2,4], [2,13,1000000000]]

Step 1: Compute Prefix Sums
prefix = [0, 7, 11, 16, 19, 27]

Query 1: [0,2,2]
- favoriteType = 0, favoriteDay = 2, dailyCap = 2
- Candies eaten by day 2: [3, 6]
- Type 0 candies: [1, 7]
- Overlap: max(3,1) = 3, min(6,7) = 6, so 3 <= 6True

Query 2: [4,2,4]
- Type 4 starts at prefix[4]+1 = 20, ends at 27
- By day 2: [3,12]
- Overlap: max(3,20) = 20, min(12,27) = 12, so 20 > 12False

Query 3: [2,13,1000000000]
- Type 2 starts at prefix[2]+1 = 12, ends at 16
- By day 13: [14, 14000000000]
- Overlap: max(14,12) = 14, min(14000000000,16) = 16, so 14 <= 16True

Final Output: [True, False, True]

Time and Space Complexity

Brute-Force Approach:

  • Simulate each day for each query, which could be up to O(Q * N), where N is the number of days, which can be very large.
Optimized Approach:
  • Computing prefix sums: O(K), where K is the number of candy types.
  • Each query: O(1), since we just do arithmetic and comparisons.
  • Total: O(K + Q), where Q is the number of queries.
  • Space: O(K) for prefix sums and O(Q) for output.

This makes the optimized solution very efficient, even for large input sizes.

Summary

In this problem, we efficiently determine if it is possible to eat your favorite candy on your favorite day by using prefix sums to quickly compute how many candies you could have eaten by a certain day and how many candies are required to reach your favorite type. By checking for overlap between possible candies eaten and the candies of your favorite type, we answer each query in constant time. This approach is both elegant and optimal for the problem's constraints.

Code Implementation

from typing import List

class Solution:
    def canEat(self, candiesCount: List[int], queries: List[List[int]]) -> List[bool]:
        # Compute prefix sums
        prefix = [0]
        for count in candiesCount:
            prefix.append(prefix[-1] + count)
        
        result = []
        for t, d, cap in queries:
            # The earliest and latest candy number eaten on day d
            min_candies = d + 1
            max_candies = (d + 1) * cap
            # The range of candies belonging to type t
            type_start = prefix[t] + 1
            type_end = prefix[t + 1]
            # Check for overlap
            can = not (max_candies < type_start or min_candies > type_end)
            result.append(can)
        return result
      
class Solution {
public:
    vector<bool> canEat(vector<int>& candiesCount, vector<vector<int>>& queries) {
        int n = candiesCount.size();
        vector<long long> prefix(n + 1, 0);
        for (int i = 0; i < n; ++i) {
            prefix[i + 1] = prefix[i] + candiesCount[i];
        }
        vector<bool> result;
        for (auto& q : queries) {
            int t = q[0], d = q[1], cap = q[2];
            long long min_candies = (long long)d + 1;
            long long max_candies = (long long)(d + 1) * cap;
            long long type_start = prefix[t] + 1;
            long long type_end = prefix[t + 1];
            bool can = !(max_candies < type_start || min_candies > type_end);
            result.push_back(can);
        }
        return result;
    }
};
      
class Solution {
    public boolean[] canEat(int[] candiesCount, int[][] queries) {
        int n = candiesCount.length;
        long[] prefix = new long[n + 1];
        for (int i = 0; i < n; ++i) {
            prefix[i + 1] = prefix[i] + candiesCount[i];
        }
        boolean[] result = new boolean[queries.length];
        for (int i = 0; i < queries.length; ++i) {
            int t = queries[i][0], d = queries[i][1], cap = queries[i][2];
            long min_candies = (long)d + 1;
            long max_candies = (long)(d + 1) * cap;
            long type_start = prefix[t] + 1;
            long type_end = prefix[t + 1];
            result[i] = !(max_candies < type_start || min_candies > type_end);
        }
        return result;
    }
}
      
var canEat = function(candiesCount, queries) {
    let n = candiesCount.length;
    let prefix = new Array(n + 1).fill(0);
    for (let i = 0; i < n; ++i) {
        prefix[i + 1] = prefix[i] + candiesCount[i];
    }
    let result = [];
    for (let q of queries) {
        let t = q[0], d = q[1], cap = q[2];
        let min_candies = d + 1;
        let max_candies = (d + 1) * cap;
        let type_start = prefix[t] + 1;
        let type_end = prefix[t + 1];
        let can = !(max_candies < type_start || min_candies > type_end);
        result.push(can);
    }
    return result;
};