一、题目描述
给你一个整数数组 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
二、解题思路
这道题目典型的01背包
问题,所有的数要么选要么不选,可以用到动态规划的方法来做。
这里我们采用递归的方法来做。
首先需要对数组进行从小到大的排序。
假设dfs(i)
函数的作用是当奖励值为i
时,可以获得的最大总奖励。
dfs(i + rewardValues[j]) + rewardValues[j]
那么上面的式子表示当前奖励值i
加上奖励值rewardValues[j]
后的总奖励
但是我们要找到最大的总奖励,所以我们需要遍历整个数组 来进行比较,dfs
函数如下:
// 辅助函数,用于计算递归逻辑
int dfs(int i) {
if (i >= CACHE_SIZE) return 0; // 防止索引越界
if (cache[i] != -1) {
return cache[i]; // 如果缓存中已经有值,直接返回
}
int res = 0;
for (int j = 0; j < n; j++) {
if (i < rewardValues[j]) {
int newValue = dfs(i + rewardValues[j]) + rewardValues[j];
if (newValue > res) {
res = newValue; // 更新最大值
}
}
}
cache[i] = res; // 将结果存入缓存
return res;
}
cache[i]
数组存放在奖励i
状态下的最大总奖励,为了防止重复计算dfs(i)
三、代码
// 比较函数用于 qsort 排序
int cmp(const int* a, const int* b) {
return *a - *b;
}
#define CACHE_SIZE 2000 // 定义缓存大小
int maxTotalReward(int* rewardValues, int n) {
// 缓存数组,用来保存已计算的结果,初始化为-1
int cache[CACHE_SIZE];
for (int i = 0; i < CACHE_SIZE; i++) {
cache[i] = -1;
}
// 辅助函数,用于计算递归逻辑
int dfs(int i) {
if (i >= CACHE_SIZE) return 0; // 防止索引越界
if (cache[i] != -1) {
return cache[i]; // 如果缓存中已经有值,直接返回
}
int res = 0;
for (int j = 0; j < n; j++) {
if (i < rewardValues[j]) {
int newValue = dfs(i + rewardValues[j]) + rewardValues[j];
if (newValue > res) {
res = newValue; // 更新最大值
}
}
}
cache[i] = res; // 将结果存入缓存
return res;
}
// 对 rewardValues 进行升序排序
qsort(rewardValues, n, sizeof(int), (int (*)(const void*, const void*))cmp);
// 从初始状态 0 开始递归计算
return dfs(0);
}