【每日一题Day95】LC1815得到新鲜甜甜圈的最多组数 | 状态压缩dp 记忆化搜索

这篇具有很好参考价值的文章主要介绍了【每日一题Day95】LC1815得到新鲜甜甜圈的最多组数 | 状态压缩dp 记忆化搜索。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

得到新鲜甜甜圈的最多组数【LC1815】

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

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

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

一天不学习就又开始焦虑了 还是天天学习吧 今天的好难 respect灵神
祝大家兔年大吉钱兔无忧呀

  • 思路

    • 首先,我们需要尽可能寻找 x x x组顾客的数量之和为batchSize的倍数,那么下一组顾客一定会感到开心,以使开心的顾客总是最多【有点贪心】。
    • 比较容易写出的是一组顾客或者两组顾客的数量[两数之和]为batchSize的倍数。【计算过程中记录改组客人除以batchSize的余数,因为我们只关心是否是倍数,不关心数值的大小】
    • 由于batchSize最大值为9,因此这样计算之后,剩余没有配对的顾客,最多只有4种了,因此我们可以计算三数之和以及四数之和为batchSize的倍数的组数,如果计算完成后仍有顾客剩余,只有剩余的第一组顾客会满意,将结果+1返回即可【写不出来…】
  • 思路:假设batchSize m m m

    由于我们只关心上一批顾客购买后余下的甜甜圈数量,并且相同几组顾客到达的先后顺序不影响结果,因此存在重复子问题,可以用记忆化搜索最优的顾客顺序对应的分数,并使用状态压缩记录剩下顾客团体的个数以及上一批顾客购买后余下的甜甜圈数量,便于使用位运算进行状态的遍历及转移

    • 记忆化搜索过程

      • 当前操作:枚举 [ 0 , n − 1 ] [0,n-1] [0,n1] c n t [ x ] > 0 cnt[x]>0 cnt[x]>0 x x x,表示一批group[i] mod m = x 的顾客前来购买甜甜圈
      • 子问题、哪些操作会影响数据:余下的甜甜圈数量 l e f t left left,以及剩余可以选的元素个数 c n t [ x ] cnt[x] cnt[x]【dfs函数的两个参数->使用状态压缩至一个int类型变量中】
      • 下一个子问题:那么 l e f t left left需要修改为$(left + x)%m ,并将 ,并将 ,并将cnt[x]$减1。如果left=0时,下一批顾客会开心,结果加1
    • 状态压缩:使用int类型变量mask记录剩下顾客团体的个数以及上一批顾客购买后余下的甜甜圈数量

      【每日一题Day95】LC1815得到新鲜甜甜圈的最多组数 | 状态压缩dp 记忆化搜索

      • 由于剩下的顾客最多有4种,而 g r u o p s [ x ] ≤ 30 gruops[x] \le 30 gruops[x]30,因此可以用5个比特表示顾客 x x x的个数,一共需要20个比特,并使用 l e f t left left记录上一批顾客购买后剩下的甜甜圈数量, l e f t < 9 left \lt 9 left<9,因此需要4个比特,因此可以使用int类型变量mask记录剩下顾客团体的个数以及上一批顾客购买后余下的甜甜圈数量

      • 使用int数组记录每个顾客团体对应的顾客数量val[i],数组长度为 n n nval 越靠后的,在 mask 中的比特位越高

        比如val[0]对应mask中第0位至第4位,val[0]对应mask中第5位至第9位

    • 状态转移过程
      $$
      score=\left{
      \begin{aligned}
      1\qquad left=0 \
      0\qquad left !=0 \

      \end{aligned}
      \right.
      \
      dp[mask] = max {dp[mask],score + dfs[nextMask])}
      $$

  • 实现

    首先遍历数组,记录单组顾客以及两组是 m m m倍数的个数ans,然后使用状态压缩定义mask,记忆化搜索每个可能的状态对应的分数,并记录至map集合中,定义 d f s ( m a s k ) dfs(mask) dfs(mask) 表示剩余顾客数量和left数量为mask时,往下进行操作能获得的最大分数,那么 a n s + = d f s ( m a s k ) ans+ =dfs(mask) ans+=dfs(mask) 即为最终结果文章来源地址https://www.toymoban.com/news/detail-438476.html

    • 由于数字过大,若使用数组会造成空间浪费,因此使用map集合,存储状态对应的分数
    • 位运算操作
      • mask中取出(高4位),记为leftmask<<20
      • mask中取出剩余顾客数量(低20位),记为mskmask&((1<<20)-1)
      • msk中取出数量为val[i]对应的个数:msk>>(i*5)
      • leftmsk组合在一起:left<<20|mask-(1<<j)
    class Solution {
        private int m;
        private int[] val;
        private final Map<Integer, Integer> cache = new HashMap<>();
    
        public int maxHappyGroups(int batchSize, int[] groups) {
            m = batchSize;
            int ans = 0;
            int[] cnt = new int[m];
            // 秒啊 一次遍历解决
            for (int x : groups) {
                x %= m;
                if (x == 0) ++ans; // 直接排在最前面
                else if (cnt[m - x] > 0) {
                    --cnt[m - x]; // 配对:两组顾客的和为batchSize的倍数
                    ++ans;
                } else ++cnt[x];
            }
    		// 剩下的顾客最多有4种 统计并记录剩余顾客种类以及对应组数
            int mask = 0, n = 0;
            for (int c : cnt) if (c > 0) ++n;
            val = new int[n];// 从大到小
            for (int x = 1; x < m; ++x)
                if (cnt[x] > 0) {
                    val[--n] = x; // val 越靠后的,在 mask 中的比特位越高
                    mask = mask << 5 | cnt[x];
                }
    
            return ans + dfs(mask);
        }
    
        private int dfs(int mask) {
            if (cache.containsKey(mask)) return cache.get(mask);
            int res = 0, left = mask >> 20, msk = mask & ((1 << 20) - 1);
            for (int i = 0, j = 0; i < val.length; ++i, j += 5) // 枚举顾客
                if ((msk >> j & 31) > 0) // cnt[val[i]] > 0
                    res = Math.max(res, (left == 0 ? 1 : 0) + dfs((left + val[i]) % m << 20 | msk - (1 << j)));
            cache.put(mask, res);
            return res;
        }
    }
    
    作者:灵茶山艾府
    链接:https://leetcode.cn/problems/maximum-number-of-groups-getting-fresh-donuts/solutions/2072545/by-endlesscheng-r5ve/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    • 复杂度
      • 时间复杂度: O ( m 2 ( n m ) m / 2 ) O(m^2(\frac{n}{m})^{m/2}) O(m2(mn)m/2) n n n为数组的长度, m m mbatchSize,最坏情况下没有两个一对的,例如 groups 中只有 [1,4] 中的数。根据基本不等式,把 30 平分成 8+8+7+7 是最优的,那么至多有 9×(8×8×7×7)=28224 个状态,每个状态执行至多 4次循环,因此记忆化搜索的计算量至多为 28224×4=112896
      • 空间复杂度: O ( m ( n m ) m / 2 ) O(m(\frac{n}{m})^{m/2}) O(m(mn)m/2),主要取决于状态个数

到了这里,关于【每日一题Day95】LC1815得到新鲜甜甜圈的最多组数 | 状态压缩dp 记忆化搜索的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【每日一题Day222】LC1110删点成林 | dfs后序

    给出二叉树的根节点 root ,树上每个节点都有一个不同的值。 如果节点值在 to_delete 中出现,我们就把该节点从树上删去,最后得到一个森林(一些不相交的树构成的集合)。 返回森林中的每棵树。你可以按任意顺序组织答案。 又是一段瓶颈期 2023/5/30 思路 遍历树时,如果

    2024年02月07日
    浏览(32)
  • 【每日一题Day266】LC18四数之和 | 排序+双指针

    四数之和【 LC18 】 给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且 不重复 的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复): 0 = a, b, c, d n a 、 b 、 c 和 d 互不相同 nums[a] + nums[b]

    2024年02月16日
    浏览(30)
  • 【每日一题Day224】LC2517礼盒的最大甜蜜度 | 二分答案

    礼盒的最大甜蜜度【LC2517】 You are given an array of positive integers price where price[i] denotes the price of the ith candy and a positive integer k . The store sells baskets of k distinct candies. The tastiness of a candy basket is the smallest absolute difference of the prices of any two candies in the basket. Return the maximum tastiness of a

    2024年02月07日
    浏览(28)
  • 【每日一题Day262】LC1911最大子序列交替和 | dp

    最大子序列交替和【LC1911】 一个下标从 0 开始的数组的 交替和 定义为 偶数 下标处元素之 和 减去 奇数 下标处元素之 和 。 比方说,数组 [4,2,5,3] 的交替和为 (4 + 5) - (2 + 3) = 4 。 给你一个数组 nums ,请你返回 nums 中任意子序列的 最大交替和 (子序列的下标 重新 从 0 开始编

    2024年02月15日
    浏览(28)
  • 【每日一题Day191】LC2423删除字符使频率相同 | 枚举 分类讨论

    给你一个下标从 0 开始的字符串 word ,字符串只包含小写英文字母。你需要选择 一个 下标并 删除 下标处的字符,使得 word 中剩余每个字母出现 频率 相同。 如果删除一个字母后, word 中剩余所有字母的出现频率都相同,那么返回 true ,否则返回 false 。 注意: 字母 x 的 频

    2024年02月01日
    浏览(31)
  • 【每日一题Day208】LC1335工作计划的最低难度 | 动态规划

    工作计划的最低难度【LC1335】 你需要制定一份 d 天的工作计划表。工作之间存在依赖,要想执行第 i 项工作,你必须完成全部 j 项工作( 0 = j i )。 你每天 至少 需要完成一项任务。工作计划的总难度是这 d 天每一天的难度之和,而一天的工作难度是当天应该完成工作的最大

    2024年02月05日
    浏览(59)
  • 【每日一题Day292】LC1572矩阵对角线元素的和 模拟

    思路 简单模拟,主对角线的元素横纵坐标相等,副对角线的元素横纵坐标相加为n-1,注意避免重复计算 实现 复杂度 时间复杂度: O ( log ⁡ n ) mathcal{O}(log n) O ( lo g n ) 空间复杂度: O ( 1 ) mathcal{O}(1) O ( 1 )

    2024年02月13日
    浏览(28)
  • 【每日一题Day267】LC834树中距离之和 | 换根dp

    树中距离之和【LC834】 给定一个无向、连通的树。树中有 n 个标记为 0...n-1 的节点以及 n-1 条边 。 给定整数 n 和数组 edges , edges[i] = [ai, bi] 表示树中的节点 ai 和 bi 之间有一条边。 返回长度为 n 的数组 answer ,其中 answer[i] 是树中第 i 个节点与所有其他节点之间的距离之和。

    2024年02月16日
    浏览(28)
  • 【每日一题Day331】LC2560打家劫舍 IV | 二分查找 + 贪心

    打家劫舍 IV【LC2560】 沿街有一排连续的房屋。每间房屋内都藏有一定的现金。现在有一位小偷计划从这些房屋中窃取现金。 由于相邻的房屋装有相互连通的防盗系统,所以小偷 不会窃取相邻的房屋 。 小偷的 窃取能力 定义为他在窃取过程中能从单间房屋中窃取的 最大金额

    2024年02月07日
    浏览(31)
  • 【每日一题Day312】LC2240买钢笔和铅笔的方案数 | 完全背包 数学

    买钢笔和铅笔的方案数【LC2240】 给你一个整数 total ,表示你拥有的总钱数。同时给你两个整数 cost1 和 cost2 ,分别表示一支钢笔和一支铅笔的价格。你可以花费你部分或者全部的钱,去买任意数目的两种笔。 请你返回购买钢笔和铅笔的 不同方案数目 。 一眼背包问题 原来数

    2024年02月10日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包