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 { |