LeetCode 题解工作台

得到新鲜甜甜圈的最多组数

有一个甜甜圈商店,每批次都烤 batchSize 个甜甜圈。这个店铺有个规则,就是在烤一批新的甜甜圈时,之前 所有 甜甜圈都必须已经全部销售完毕。给你一个整数 batchSize 和一个整数数组 groups ,数组中的每个整数都代表一批前来购买甜甜圈的顾客,其中 groups[i] 表示这一批顾客…

category

5

题型

code_blocks

4

代码语言

hub

3

相关题

当前训练重点

困难 · 状态·转移·动态规划

bolt

答案摘要

题目实际上要我们找到一种安排顺序,使得前缀和(这里指的是“人数”)与 取模后为 的组数最多。因此,我们可以将所有顾客按组分成两类: - 人数为 的整数倍的顾客,这些顾客不会对下一组顾客的甜甜圈产生影响,我们可以贪心地优先安排这些组的顾客,那么这些组的顾客都会感到开心,“初始答案”为这些组的数量;

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

有一个甜甜圈商店,每批次都烤 batchSize 个甜甜圈。这个店铺有个规则,就是在烤一批新的甜甜圈时,之前 所有 甜甜圈都必须已经全部销售完毕。给你一个整数 batchSize 和一个整数数组 groups ,数组中的每个整数都代表一批前来购买甜甜圈的顾客,其中 groups[i] 表示这一批顾客的人数。每一位顾客都恰好只要一个甜甜圈。

当有一批顾客来到商店时,他们所有人都必须在下一批顾客来之前购买完甜甜圈。如果一批顾客中第一位顾客得到的甜甜圈不是上一组剩下的,那么这一组人都会很开心。

你可以随意安排每批顾客到来的顺序。请你返回在此前提下,最多 有多少组人会感到开心。

 

示例 1:

输入:batchSize = 3, groups = [1,2,3,4,5,6]
输出:4
解释:你可以将这些批次的顾客顺序安排为 [6,2,4,5,1,3] 。那么第 1,2,4,6 组都会感到开心。

示例 2:

输入:batchSize = 4, groups = [1,3,2,5,2,2,1,6]
输出:4

 

提示:

  • 1 <= batchSize <= 9
  • 1 <= groups.length <= 30
  • 1 <= groups[i] <= 109
lightbulb

解题思路

方法一:贪心 + 状态压缩 + 记忆化搜索

题目实际上要我们找到一种安排顺序,使得前缀和(这里指的是“人数”)与 batchSizebatchSize 取模后为 00 的组数最多。因此,我们可以将所有顾客按组分成两类:

  • 人数为 batchSizebatchSize 的整数倍的顾客,这些顾客不会对下一组顾客的甜甜圈产生影响,我们可以贪心地优先安排这些组的顾客,那么这些组的顾客都会感到开心,“初始答案”为这些组的数量;
  • 人数不为 batchSizebatchSize 的整数倍的顾客,这些顾客的安排顺序会影响下一组顾客的甜甜圈。我们可以对这里每一组的人数 vvbatchSizebatchSize,得到的这些余数构成一个集合,集合中的元素值范围是 [1,2...,batchSize1][1,2...,batchSize-1]。数组 groupsgroups 的长度最大为 3030,因此,每个余数的数量最大不超过 3030。我们可以用 55 个二进制位来表示一个余数的数量,而 batchSizebatchSize 最大为 99,那么表示这些余数以及对应的数量总共需要的二进制位就是 5×(91)=405\times (9-1)=40。我们可以用一个 6464 位整数 statestate 来表示。

接下来,我们设计一个函数 dfs(state,mod)dfs(state, mod),表示安排状态为 statestate,且当前前缀余数为 modmod 时,能使得多少组感到开心。那么我们在“初始答案”加上 dfs(state,0)dfs(state, 0),即为最终答案。

函数 dfs(state,mod)dfs(state, mod) 的实现逻辑如下:

我们枚举 11batchSize1batchSize-1 的每一个余数 ii,如果余数 ii 的数量不为 00,那么我们可以将余数 ii 的数量减去 11,将当前前缀余数加上 ii 并且对 batchSizebatchSize 取模,然后递归调用函数 dfsdfs,求出子状态的最优解,取最大值即可。最后判断 modmod 是否为 00,如果为 00,我们在最大值上加 11 后返回,否则直接返回最大值。

过程中,我们可以使用记忆化搜索来避免状态的重复计算。

时间复杂度不超过 O(107)O(10^7),空间复杂度不超过 O(106)O(10^6)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
    def maxHappyGroups(self, batchSize: int, groups: List[int]) -> int:
        @cache
        def dfs(state, mod):
            res = 0
            x = int(mod == 0)
            for i in range(1, batchSize):
                if state >> (i * 5) & 31:
                    t = dfs(state - (1 << (i * 5)), (mod + i) % batchSize)
                    res = max(res, t + x)
            return res

        state = ans = 0
        for v in groups:
            i = v % batchSize
            ans += i == 0
            if i:
                state += 1 << (i * 5)
        ans += dfs(state, 0)
        return ans
speed

复杂度分析

指标
时间complexity is roughly O(batchSize^groups.length) due to all possible state combinations, reduced with memoization and pruning. Space complexity is O(batchSize^groups.length) for memoization storage.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Noticing that direct permutation is infeasible due to group length.

  • question_mark

    Observing that happy groups depend on sum modulo batchSize.

  • question_mark

    Asking for dynamic programming optimization using remainders.

warning

常见陷阱

外企场景
  • error

    Forgetting that only the first customer in a batch affects happiness.

  • error

    Neglecting groups that are multiples of batchSize which are immediately happy.

  • error

    Failing to memoize states leading to TLE on larger inputs.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Maximize happy groups with variable batch sizes per day.

  • arrow_right_alt

    Compute minimum leftover donuts while maximizing happy groups.

  • arrow_right_alt

    Adapt the solution to include group-specific donut preferences affecting happiness.

help

常见问题

外企场景

得到新鲜甜甜圈的最多组数题解:状态·转移·动态规划 | LeetCode #1815 困难