LeetCode 2218. 从栈中取出K个硬币的最大面值和(hard)

题目

LeetCode 2218. 从栈中取出K个硬币的最大面值和(hard)

一张桌子上总共有 n 个硬币 。每个栈有 正整数 个带面值的硬币。

每一次操作中,你可以从任意一个栈的 顶部 取出 1 个硬币,从栈中移除它,并放入你的钱包里。

给你一个列表 piles ,其中 piles[i] 是一个整数数组,分别表示第 i 个栈里 从顶到底 的硬币面值。同时给你一个正整数 k ,请你返回在 恰好 进行 k 次操作的前提下,你钱包里硬币面值之和 最大为多少

示例 1:

ex.jpg

输入:piles = [[1,100,3],[7,8,9]], k = 2
输出:101
解释:
上图展示了几种选择 k 个硬币的不同方法。
我们可以得到的最大面值为 101 。

示例 2:

输入:piles = [[100],[100],[100],[100],[100],[100],[1,1,1,1,1,1,700]], k = 7
输出:706
解释:
如果我们所有硬币都从最后一个栈中取,可以得到最大面值和。

提示:

  • n == piles.length
  • 1 <= n <= 1000
  • 1 <= piles[i][j] <= 105
  • 1 <= k <= sum(piles[i].length) <= 2000

解释

① 把背包容量看成k,每个栈代表一种物品,所需容量为从此栈中取出的数的个数,跟一般的0-1背包不同的是,这里每个物品所占的容量是会变化的,取决于从这个栈里取多少数出来
② 对于第i个物品,即第i个栈,遍历其可能拿出的数所有情况。j代表到第i个栈为止一共往背包里装了多少个数。l代表从第i个栈里取出了多少个数。即有转移方程dp[i][j] = max(dp[i][j], dp[i - 1][j - l] + piles[i - 1][l - 1]),其中piles[i - 1][l - 1]已经是前缀和
③ 这里需要注意for循环的范围:

  • i的范围为第1个栈到第n个栈,所以转化为下标、取对应的前缀和piles[i - 1][l - 1]时,i需要减一
  • j代表到第i个栈为止一共往背包里装了多少个数,最大不能超过k,但同时也不能超过从第1个栈到第i个栈为止所有栈中的数的个数之和,因为显然不能将所有栈中的数字都取出来后再继续取。因此需要一个sum来记录。还有,从当前栈中不取任何数的情况单独处理,不放进for循环中,因此j >= 1
  • l代表从第i个栈里取出了多少个数,不能超过当前栈的数的总数,也不能超过当前假定的、到这个栈为止一共往背包里装了多少个数,即j

代码(C++实现)

class Solution {
public:
    int maxValueOfCoins(vector<vector<int>>& piles, int k) {
        int n = piles.size();
        vector<vector<int>> dp(n + 1, vector<int>(k + 1, 0));
        int ret = 0;
        int sum = 0;
        for (int i = 1; i <= n; ++i) {
            sum += piles[i - 1].size();
            for (int j = 1; j < piles[i - 1].size(); ++j)
                piles[i - 1][j] += piles[i - 1][j - 1];
            for (int j = 1; j <= k && j <= sum; ++j) {
                dp[i][j] = dp[i - 1][j];
                for (int l = 1; l <= j && l <= piles[i - 1].size(); ++l) {
                    dp[i][j] = max(dp[i][j], dp[i - 1][j - l] + piles[i - 1][l - 1]);
                }
                ret = max(ret, dp[i][j]);
            }
        }
        return ret;
    }
};

有收获的话,求个赞~ Click Here

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-value-of-k-coins-from-piles

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Air浩瀚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值