Every day a Leetcode
解法1:bitset/bigint 优化 0-1 背包
对于数组 rewardValues 中的数,如果先选大的,就没法再选小的,所以按照从小到大的顺序选是最好的。
把 rewardValues 从小到大排序。
排序后,问题变成一个标准的 0-1 背包问题。
对于本题,定义 f[i][j] 表示能否从前 i 个数中得到总奖励 j。
本题范围很大,需要去掉第一个维度,并用 bitset 优化(也可以用 bigint)。
代码:
/*
* @lc app=leetcode.cn id=3181 lang=cpp
*
* [3181] 执行操作可获得的最大总奖励 II
*/
// @lc code=start
class Solution
{
public:
int maxTotalReward(vector<int> &rewardValues)
{
ranges::sort(rewardValues);
rewardValues.erase(unique(rewardValues.begin(), rewardValues.end()), rewardValues.end());
bitset<100000> f{1};
for (int v : rewardValues)
{
int shift = f.size() - v;
// 左移 shift 再右移 shift,把所有 >= v 的比特位置 0
// f |= f << shift >> shift << v;
f |= f << shift >> (shift - v); // 简化上式
}
for (int i = rewardValues.back() * 2 - 1;; i--)
if (f.test(i))
return i;
}
};
// @lc code=end
结果:
复杂度分析:
时间复杂度:O(n*m/w),其中 n 是数组 rewardValues 的长度,m=max(rewardValues),w =64 或 32。
空间复杂度:O(n+m/w),其中 n 是数组 rewardValues 的长度,m=max(rewardValues),w =64 或 32。