comments | difficulty | edit_url | rating | source | tags | ||
---|---|---|---|---|---|---|---|
true |
中等 |
1848 |
第 401 场周赛 Q3 |
|
给你一个整数数组 rewardValues
,长度为 n
,代表奖励的值。
最初,你的总奖励 x
为 0,所有下标都是 未标记 的。你可以执行以下操作 任意次 :
- 从区间
[0, n - 1]
中选择一个 未标记 的下标i
。 - 如果
rewardValues[i]
大于 你当前的总奖励x
,则将rewardValues[i]
加到x
上(即x = x + rewardValues[i]
),并 标记 下标i
。
以整数形式返回执行最优操作能够获得的 最大 总奖励。
示例 1:
输入:rewardValues = [1,1,3,3]
输出:4
解释:
依次标记下标 0 和 2,总奖励为 4,这是可获得的最大值。
示例 2:
输入:rewardValues = [1,6,4,3,2]
输出:11
解释:
依次标记下标 0、2 和 1。总奖励为 11,这是可获得的最大值。
提示:
1 <= rewardValues.length <= 2000
1 <= rewardValues[i] <= 2000
我们可以对奖励值数组 rewardValues
进行排序,然后使用记忆化搜索的方法求解最大总奖励。
我们定义一个函数
函数
- 二分查找数组
rewardValues
中第一个大于$x$ 的元素的下标$i$ ; - 遍历数组
rewardValues
中从下标$i$ 开始的元素,对于每个元素$v$ ,计算$v + \textit{dfs}(x + v)$ 的最大值。 - 将结果返回。
为了避免重复计算,我们使用记忆化数组 f
记录已经计算过的结果。
时间复杂度 rewardValues
的长度,而 rewardValues
中的最大值的两倍。
class Solution:
def maxTotalReward(self, rewardValues: List[int]) -> int:
@cache
def dfs(x: int) -> int:
i = bisect_right(rewardValues, x)
ans = 0
for v in rewardValues[i:]:
ans = max(ans, v + dfs(x + v))
return ans
rewardValues.sort()
return dfs(0)
class Solution {
private int[] nums;
private Integer[] f;
public int maxTotalReward(int[] rewardValues) {
nums = rewardValues;
Arrays.sort(nums);
int n = nums.length;
f = new Integer[nums[n - 1] << 1];
return dfs(0);
}
private int dfs(int x) {
if (f[x] != null) {
return f[x];
}
int i = Arrays.binarySearch(nums, x + 1);
i = i < 0 ? -i - 1 : i;
int ans = 0;
for (; i < nums.length; ++i) {
ans = Math.max(ans, nums[i] + dfs(x + nums[i]));
}
return f[x] = ans;
}
}
class Solution {
public:
int maxTotalReward(vector<int>& rewardValues) {
sort(rewardValues.begin(), rewardValues.end());
int n = rewardValues.size();
int f[rewardValues.back() << 1];
memset(f, -1, sizeof(f));
function<int(int)> dfs = [&](int x) {
if (f[x] != -1) {
return f[x];
}
auto it = upper_bound(rewardValues.begin(), rewardValues.end(), x);
int ans = 0;
for (; it != rewardValues.end(); ++it) {
ans = max(ans, rewardValues[it - rewardValues.begin()] + dfs(x + *it));
}
return f[x] = ans;
};
return dfs(0);
}
};
func maxTotalReward(rewardValues []int) int {
sort.Ints(rewardValues)
n := len(rewardValues)
f := make([]int, rewardValues[n-1]<<1)
for i := range f {
f[i] = -1
}
var dfs func(int) int
dfs = func(x int) int {
if f[x] != -1 {
return f[x]
}
i := sort.SearchInts(rewardValues, x+1)
f[x] = 0
for _, v := range rewardValues[i:] {
f[x] = max(f[x], v+dfs(x+v))
}
return f[x]
}
return dfs(0)
}
function maxTotalReward(rewardValues: number[]): number {
rewardValues.sort((a, b) => a - b);
const search = (x: number): number => {
let [l, r] = [0, rewardValues.length];
while (l < r) {
const mid = (l + r) >> 1;
if (rewardValues[mid] > x) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
};
const f: number[] = Array(rewardValues.at(-1)! << 1).fill(-1);
const dfs = (x: number): number => {
if (f[x] !== -1) {
return f[x];
}
let ans = 0;
for (let i = search(x); i < rewardValues.length; ++i) {
ans = Math.max(ans, rewardValues[i] + dfs(x + rewardValues[i]));
}
return (f[x] = ans);
};
return dfs(0);
}
我们定义
我们考虑第
最终答案为
由于
时间复杂度 rewardValues
的长度,而 rewardValues
中的最大值的两倍。
class Solution:
def maxTotalReward(self, rewardValues: List[int]) -> int:
nums = sorted(set(rewardValues))
m = nums[-1] << 1
f = [False] * m
f[0] = True
for v in nums:
for j in range(m):
if 0 <= j - v < v:
f[j] |= f[j - v]
ans = m - 1
while not f[ans]:
ans -= 1
return ans
class Solution {
public int maxTotalReward(int[] rewardValues) {
int[] nums = Arrays.stream(rewardValues).distinct().sorted().toArray();
int n = nums.length;
int m = nums[n - 1] << 1;
boolean[] f = new boolean[m];
f[0] = true;
for (int v : nums) {
for (int j = 0; j < m; ++j) {
if (0 <= j - v && j - v < v) {
f[j] |= f[j - v];
}
}
}
int ans = m - 1;
while (!f[ans]) {
--ans;
}
return ans;
}
}
class Solution {
public:
int maxTotalReward(vector<int>& rewardValues) {
sort(rewardValues.begin(), rewardValues.end());
rewardValues.erase(unique(rewardValues.begin(), rewardValues.end()), rewardValues.end());
int n = rewardValues.size();
int m = rewardValues.back() << 1;
bool f[m];
memset(f, false, sizeof(f));
f[0] = true;
for (int v : rewardValues) {
for (int j = 1; j < m; ++j) {
if (0 <= j - v && j - v < v) {
f[j] = f[j] || f[j - v];
}
}
}
int ans = m - 1;
while (!f[ans]) {
--ans;
}
return ans;
}
};
func maxTotalReward(rewardValues []int) int {
slices.Sort(rewardValues)
nums := slices.Compact(rewardValues)
n := len(nums)
m := nums[n-1] << 1
f := make([]bool, m)
f[0] = true
for _, v := range nums {
for j := 1; j < m; j++ {
if 0 <= j-v && j-v < v {
f[j] = f[j] || f[j-v]
}
}
}
ans := m - 1
for !f[ans] {
ans--
}
return ans
}
function maxTotalReward(rewardValues: number[]): number {
const nums = Array.from(new Set(rewardValues)).sort((a, b) => a - b);
const n = nums.length;
const m = nums[n - 1] << 1;
const f: boolean[] = Array(m).fill(false);
f[0] = true;
for (const v of nums) {
for (let j = 1; j < m; ++j) {
if (0 <= j - v && j - v < v) {
f[j] = f[j] || f[j - v];
}
}
}
let ans = m - 1;
while (!f[ans]) {
--ans;
}
return ans;
}
我们可以对方法二进行优化,定义一个二进制数
观察方法二的状态转移方程
那么答案为
时间复杂度 rewardValues
的长度,而 rewardValues
中的最大值的两倍。整数
class Solution:
def maxTotalReward(self, rewardValues: List[int]) -> int:
nums = sorted(set(rewardValues))
f = 1
for v in nums:
f |= (f & ((1 << v) - 1)) << v
return f.bit_length() - 1
import java.math.BigInteger;
import java.util.Arrays;
class Solution {
public int maxTotalReward(int[] rewardValues) {
int[] nums = Arrays.stream(rewardValues).distinct().sorted().toArray();
BigInteger f = BigInteger.ONE;
for (int v : nums) {
BigInteger mask = BigInteger.ONE.shiftLeft(v).subtract(BigInteger.ONE);
BigInteger shifted = f.and(mask).shiftLeft(v);
f = f.or(shifted);
}
return f.bitLength() - 1;
}
}
class Solution {
public:
int maxTotalReward(vector<int>& rewardValues) {
sort(rewardValues.begin(), rewardValues.end());
rewardValues.erase(unique(rewardValues.begin(), rewardValues.end()), rewardValues.end());
bitset<100000> f{1};
for (int v : rewardValues) {
int shift = f.size() - v;
f |= f << shift >> (shift - v);
}
for (int i = rewardValues.back() * 2 - 1;; i--) {
if (f.test(i)) {
return i;
}
}
}
};
func maxTotalReward(rewardValues []int) int {
slices.Sort(rewardValues)
rewardValues = slices.Compact(rewardValues)
one := big.NewInt(1)
f := big.NewInt(1)
p := new(big.Int)
for _, v := range rewardValues {
mask := p.Sub(p.Lsh(one, uint(v)), one)
f.Or(f, p.Lsh(p.And(f, mask), uint(v)))
}
return f.BitLen() - 1
}