LeetCode 1049 最后一块石头的重量II
有一堆石头,用整数数组 stones
表示。其中 stones[i]
表示第 i
块石头的重量。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x
和 y
,且 x <= y
。那么粉碎的可能结果如下:
- 如果
x == y
,那么两块石头都会被完全粉碎; - 如果
x != y
,那么重量为x
的石头将会完全粉碎,而重量为y
的石头新重量为y-x
。
最后,最多只会剩下一块石头。返回此石头最小的可能重量。如果没有石头剩下,就返回0。
示例:
输入:stones = [2,7,4,1,8,1]
输出:1
解释:
组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。
动态规划
此处的题设中,对于石头选取的要求是任意选取,但是要求返回的内容是最后剩余石头的最小可能重量,本质上还是在求解问题的最优解。
重点还是在于问题的划分。首先,需要对问题进行转换,将上述问题转化为:将石头分为重量作为接近的两堆,那么最后剩余的最小石头重量就是两堆石头重点之间的差值,并且对于两堆石头的数量没有任何要求。
假设第一堆石头为:
- 动态规划数据的定义:首先计算总体的石头的重量
sum
,然后令n=sum//2
,定义动态规划数组dp[n]
表示容量为n
的背包能否恰好装满,初始时仅在元素0
中选取。
\ 动态规划数组的推导:在第
i
次迭代中,从元素0-i
中选取,向背包中添加石头。那么dp[j]=dp[j]||dp[j-stones[i]] if j>=stones[i] else dp[j]
动态规划数组的初始化:首先全部初始化为
false
,当背包容量为0时,本身就是装满的状态:dp[0]=true
,若是n>=stones[0]
那么dp[stones[0]]=true
数组的便利顺序:外层循环,对石头进行遍历,
i=1,...,stones.size()-1
,内层循环对背包进行遍历,j=n,...,stones[i]
,在完成迭代后,再对dp[n]
从后向前遍历寻找第一个为true
的元素dp[k]
,那么那么最终的结果为sum-2k
。举例验证:
stones = [2,7,4,1,8,1]
初始的动态规划数组:[1,0,1,0,0,0,0,0,0,0,0,0]
逐次迭代的动态规划数组:
[1,0,1,0,0,0,0,1,0,1,0,0]
[1,0,1,0,1,0,1,1,0,1,0,1]
[1,1,1,1,1,1,1,1,1,1,1,1]
[1,1,1,1,1,1,1,1,1,1,1,1]
[1,1,1,1,1,1,1,1,1,1,1,1]
最终的输出为0
代码实现:
1 | class Solution { |