3181. 执行操作可获得的最大总奖励 II

Powered by:NEFU AB-IN

Link

3181. 执行操作可获得的最大总奖励 II

题意

给你一个整数数组 rewardValues,长度为 n,代表奖励的值。

最初,你的总奖励 x 为 0,所有下标都是 未标记 的。你可以执行以下操作 任意次 :

从区间 [0, n - 1] 中选择一个 未标记 的下标 i。
如果 rewardValues[i] 大于 你当前的总奖励 x,则将 rewardValues[i] 加到 x 上(即 x = x + rewardValues[i]),并 标记 下标 i。
以整数形式返回执行最优操作能够获得的 最大 总奖励。

思路

https://leetcode.cn/problems/maximum-total-reward-using-operations-ii/solutions/2805413/bitset-you-hua-0-1-bei-bao-by-endlessche-m1xn/

https://leetcode.cn/problems/maximum-total-reward-using-operations-i/solutions/2805418/di-tui-bitset-you-hua-by-tsreaper-c535/

定义 dp[i][j] 表示能否从前 i 个数中得到总奖励 j,由或运算进行转化

正常dp

class Solution:
    def maxTotalReward(self, rewardValues: List[int]) -> int:
        rewardValues.sort()
        rewardValues = [0] + rewardValues
        n = len(rewardValues) - 1
        m = rewardValues[-1] * 2  # 最大的可能是最大值*2

        dp = Arr.array2d(False, n + 1, m + 1, )
        dp[0][0] = True

        for i in range(1, n + 1):
            for j in range(m):
                v = rewardValues[i]
                dp[i][j] = dp[i - 1][j] or (dp[i - 1][j - v] and v <= j < 2 * v)

        for j in range(m - 1, -1, -1):
            if dp[n][j]:
                return j
        return 0

但可以注意到优化:

  1. 没必要每次都把j从0到m枚一遍(因为不满足j∈[v,2v)的dp[i][j]一定等于dp[i-1][j]),可以直接先复制dp[i-1]行
  2. 类似的删除第一个维度,从后往前遍历

得到

class Solution:
    def maxTotalReward(self, rewardValues: List[int]) -> int:
        rewardValues.sort()
        rewardValues = [0] + rewardValues
        n = len(rewardValues) - 1
        m = rewardValues[-1] * 2  # 最大的可能是最大值*2

        dp = Arr.array(False, m + 1, )
        dp[0] = True

        for i in range(1, n + 1):
            v = rewardValues[i]
            for j in range(2 * v - 1, v - 1, -1):
                dp[j] = dp[j] or dp[j - v]

        for j in range(m - 1, -1, -1):
            if dp[j]:
                return j
        return 0

但如果是这样,还是空间复杂度不够,可以采取状态压缩

  1. 因为只有v, 2v这个区间的在变,所以我们需要让这个区间的数 或 上一个状态的 0, v
  2. 首先创建掩码,将 f 的低v位通过与运算取出来
  3. 左移v位,最后或即可

代码

    def maxTotalReward(self, rewardValues: List[int]) -> int:
        rewardValues.sort()
        f = 1
        for v in rewardValues:
            mask = (1 << v) - 1
            f |= (f & mask) << v
        return f.bit_length() - 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

NEFU AB-IN

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

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

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

打赏作者

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

抵扣说明:

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

余额充值