Problem Description
We are given a donut shop that bakes donuts in batches of a fixed size (batchSize). Each arriving group of customers must be served in its entirety before moving to the next group and is happy only when the first customer in the group receives a freshly baked donut (i.e. not a leftover from a previous group). Given the sizes of the groups, we can rearrange their order arbitrarily. The goal is to maximize the number of happy groups after serving all groups in some order.
Key Insights
- Groups whose sizes are perfectly divisible by batchSize (remainder 0) are immediately happy.
- For the remaining groups, compute each group’s remainder when divided by batchSize.
- Use dynamic programming (DP) with memoization to explore the different orders in which groups (characterized by their remainders) can be served.
- The DP state tracks the counts of groups for each remainder and the current leftover donuts from previous batches.
- When a group's remainder added to the leftover becomes 0 modulo batchSize, that group will be happy.
- Because batchSize is small (up to 9) and groups length is at most 30, the combinatorial state can be efficiently cached.
Space and Time Complexity
Time Complexity: O(state_size * batchSize) where state_size depends on the counts of remainder groups. In worst-case the exploration is exponential in small numbers, which is viable given the constraints. Space Complexity: O(state_size) due to memoization caching intermediate DP state results.
Solution
We start by counting groups with no remainder (i.e. groups that directly make a fresh batch) and then reduce other groups into their modulo remainder counts. We then define a recursive DP (DFS) method that, given the current state (the frequency of each remainder and the leftover donuts), tries all possible decisions:
- Pick a group (denoted by its remainder) that remains in the state.
- Update the leftover donuts as (current leftover + r) mod batchSize.
- If the current leftover was 0, then the group being served gets a fresh batch, which counts as an additional happy group.
- Recursively solve for the new state and choose the transition that maximizes the overall number of happy groups. Memoization is used to cache the outcomes for a given state, identified by the counts and current leftover, thereby avoiding redundant computations.