leetcode
leetcode 1601 ~ 1650
得到新鲜甜甜圈的最多组数

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

难度:

标签:

题目描述

代码结果

运行时间: 40 ms, 内存: 17.1 MB


/*
 * 思路:
 * 1. 计算每个group对batchSize的余数,统计每个余数的数量。
 * 2. 如果余数为0的组,可以直接使顾客开心。
 * 3. 对于其他余数,通过配对使顾客开心。
 * 4. 使用深度优先搜索(DFS)或动态规划(DP)来优化配对过程。
 */

import java.util.*;
import java.util.stream.*;

public class DonutShopStream {
    public int maxHappyGroups(int batchSize, int[] groups) {
        Map<Integer, Long> count = Arrays.stream(groups)
            .mapToObj(g -> g % batchSize)
            .collect(Collectors.groupingBy(g -> g, Collectors.counting()));

        int happyGroups = count.getOrDefault(0, 0L).intValue();
        int left = 1, right = batchSize - 1;

        while (left < right) {
            int min = Math.min(count.getOrDefault(left, 0L).intValue(), count.getOrDefault(right, 0L).intValue());
            happyGroups += min;
            count.put(left, count.getOrDefault(left, 0L) - min);
            count.put(right, count.getOrDefault(right, 0L) - min);
            left++;
            right--;
        }

        if (batchSize % 2 == 0) {
            happyGroups += count.getOrDefault(batchSize / 2, 0L).intValue() / 2;
        }

        return happyGroups;
    }

    public static void main(String[] args) {
        DonutShopStream shop = new DonutShopStream();
        int batchSize = 4;
        int[] groups = {1, 3, 2, 5, 2, 2, 1, 6};
        System.out.println(shop.maxHappyGroups(batchSize, groups)); // 输出: 4
    }
}

解释

方法:

该题解使用了贪心策略和深度优先搜索(DFS)结合记忆化递归的方法。首先,遍历所有顾客组,将每组顾客人数对batchSize取模后的余数记录在频率数组freq中,同时统计可以直接满足条件的组数(余数为0或者存在互补的余数对)。然后,使用记忆化的DFS来处理剩余的顾客组,尝试不同的顺序来最大化满足条件的组数。在DFS中,根据当前剩余的甜甜圈数量和各余数的频率,递归地探索不同的选择,并返回最大的满足条件的组数。

时间复杂度:

O((batchSize - 1) ^ groups.length)

空间复杂度:

O((batchSize - 1) ^ groups.length)

代码细节讲解

🦆
在题解中,为什么需要将每组顾客人数对batchSize取模,这个操作的目的是什么?
在题解中,将每组顾客人数对batchSize取模的操作是为了简化问题。这是因为题目中涉及的是组数的最大化,而不是具体的顾客人数。通过取模操作,可以将问题转化为处理顾客组与batchSize的余数问题,这样就可以只关注余数,而不是具体的顾客数量。这种转化可以有效地减少问题的复杂度,因为处理的变量(余数)数量最多只有batchSize个。
🦆
题解提到了'存在互补的余数对'这一概念,具体是如何定义互补的余数对,以及它们是如何影响开心组数的增加?
互补的余数对是指两个数的余数和等于batchSize的一对值。例如,如果batchSize是5,那么余数1和4,余数2和3,以及余数0和5(如果有余数5的话)都是互补的余数对。在题解中,当检测到存在互补的余数对时,可以直接将这一对顾客组算作满足条件的组,因为它们加起来的总数正好是batchSize的倍数。这样做可以直接增加开心组数,因为每找到一对互补的余数对,就意味着有一组额外的顾客可以完全分配甜甜圈,从而增加满足条件的组数。
🦆
题解中使用了记忆化的DFS来处理剩余的顾客组,具体来说,状态的记忆化是基于哪些变量实现的?
题解中的记忆化DFS是基于两个主要变量实现的:当前剩余的甜甜圈数量(left)和各余数的频率数组(cnt)。状态的记忆化是通过缓存已经计算过的(left, cnt)组合的结果来实现的。这种方法可以避免重复计算相同状态下的结果,从而大大提高算法的效率。每个状态代表了一个特定的余数组合以及相应的剩余甜甜圈数量,其结果表示从该状态开始可以额外满足的最大组数。
🦆
在DFS函数中,参数left代表什么意义?它如何影响递归过程中的决策?
在DFS函数中,参数left表示当前剩余甜甜圈数量对batchSize的余数。它的主要作用是帮助判断加上当前选择的顾客组之后是否能形成一个完整的batchSize倍数,即是否能够形成一个新的满足条件的组。在递归过程中,通过更新left来模拟分配甜甜圈给当前选择的顾客组后的情况。如果在选择某个余数后left变为0,表示当前的选择可以使得总数达到batchSize的倍数,从而形成一个新的满足条件的组。这个参数对于决策过程至关重要,因为它直接影响了每一步选择后的状态和最终能够满足条件的组数。

相关问题