题目描述
执行操作可获得的最大总奖励 I
给你一个整数数组 rewardValues,长度为 n,代表奖励的值。
最初,你的总奖励 x 为 0,所有下标都是 未标记 的。你可以执行以下操作 任意次 :
从区间 [0, n - 1] 中选择一个 未标记 的下标 i。
如果 rewardValues[i] 大于 你当前的总奖励 x,则将 rewardValues[i] 加到 x 上(即 x = x + rewardValues[i]),并 标记 下标 i。
以整数形式返回执行最优操作能够获得的 最大 总奖励。
示例
输入:rewardValues = [1,1,3,3]
输出:4
解释:
依次标记下标 0 和 2,总奖励为 4,这是可获得的最大值。
提示:
1 <= rewardValues.length <= 2000
1 <= rewardValues[i] <= 2000
关于动态规划
这两天在看算法书,动态规划篇中以背包问题为例。但与这题有一点不同,背包问题中使用二维数组,其含义是,对于一个给定的空间,可以通过遍历数组使得让这一个空间利用率最高。如何实现?简单来说就是:
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
−
1
]
[
j
−
s
p
a
c
e
[
i
]
]
+
v
a
l
u
e
[
i
]
)
dp[i][j]=max(dp[i-1][j], dp[i-1][j-space[i]]+value[i])
dp[i][j]=max(dp[i−1][j],dp[i−1][j−space[i]]+value[i])
其中,
s
p
a
c
e
[
i
]
space[i]
space[i]为当前元素占用空间,
v
a
l
u
e
[
i
]
value[i]
value[i]为当前元素价值。
也许再看完两本算法书,我会再写一篇文章讲讲我对动态规划的看法。
这一题不需要用到二维数组,而且这一题的思路与上述差异也较大。我们接下来分析。
题目分析
首先对数组进行排序。
我们从最小的开始,再看看第二小的(我们假设每个元素不相同),如果数组就这两个元素,那直接返回求和数就行。
但当出现第三个元素之后,考虑的就多了。
首先要判断,第三个元素是不是大于前两个元素之和?如果大于,那求和就行。
但如果小于等于,那么很显然就要求和第2,3个元素。
接下来我们引入第四个元素,事情变得更复杂了!
文字叙述已经有点困难了,此处请用手算。
这时我们引入一个二维坐标轴,横轴坐标是总和(这个总和可以取很大,但必须大于所有元素的和),纵轴是数组元素的索引,记录着这个元素的值。(可以在坐标轴旁边标上值!)
横轴是从1开始的(1,2,3…),一直到那一个总和。
我们假装
(
1
,
1
)
(1,1)
(1,1)是坐标原点,从这一行开始往右写,如果目前有可以达到横坐标值的取法,那就在那里填上1。比如说我们第一个元素是1,那么我们就在
(
1
,
1
)
(1,1)
(1,1)填上1,但如果我们第一个元素是2,那
(
1
,
1
)
(1,1)
(1,1)就应该填0了,因为取不到。同理,当第一个元素是1,那么
(
2
,
1
)
(2,1)
(2,1)处就要填0了,而且这一行其他的坐标都要填上0。
写完了第一行,我们开始写第二行。假如第二个元素是3。我们从 ( 1 , 2 ) (1,2) (1,2)开始,这个坐标可以填1吗?答案是可以,因为第一个元素是1,使目前所有元素总和为1是可能的,也就是说,其实我们定义数组的时候只需要一维就可以了。然后是 ( 2 , 2 ) (2,2) (2,2),这个点不能填1。(2,3)就可以了,同理(2,4)也可以,因为1+3=4,然后(2,5)又不行了。
尝试自创一个数组,然后按这种方式填表。
我们就会发现:如果一个元素为x,目前的和(就是横坐标)是sum,如果sum-x<x,那么这个点能否填1,就只和sum-x的值有关! 因为如果sum-x是1,就意味着前面有某种方法能够使总和为这个值,而这个值又符合比x小的条件,那么我们加上x就是目前的最佳情况!!!
很烂的题解
rewardValues = [6,13,9,19] // 题目给出
s = 2*max(rewardValues)
dp = [0]*s
rewardValues.sort()
sort = rewardValues
for i in range(s):
if sort[0] == i:
dp[i] = 1
else:
dp[i] = 0
// 初始化,没用的代码
for i in range(1, len(rewardValues)):
for j in range(s):
if sort[i] == j:
dp[j] = 1 // 继承上一个节点的值
elif (sort[i] < j) and (j-sort[i] < sort[i]) and dp[j-sort[i]] == 1:
dp[j] = 1
for i in range(s-1, 0, -1):
if dp[i] == 1:
res = i
break
print(res)
总结
这道题用0和1的flag判断能不能取到值,与我最开始想的用二维数组的每个节点记录最大值有点出入,也是在这里卡了很久。
第一次比较系统地接触算法,第一次了解到动态规划,以上只是一点浅显的看法。