题目描述:
标签:动态规划
有一堆石头,每块石头的重量都是正整数。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为
x
和y
,且x <= y
。那么粉碎的可能结果如下:
- 如果
x == y
,那么两块石头都会被完全粉碎;- 如果
x != y
,那么重量为x
的石头将会完全粉碎,而重量为y
的石头新重量为y-x
。最后,最多只会剩下一块石头。返回此石头最小的可能重量。如果没有石头剩下,就返回
0
。
代码:
思路分析:动态规划五部曲
解析题目意思:就是分成两堆石头,使两堆石头的和尽量接近,才有可能剩下的石头重量最小。即背包0-1问题,找到一个sum/2的总和,即背包重量,数组元素是物品,权重和价值都是元素值stones[i]
1、确定dp数组以及下标的含义——这里dp[i]是指背包重量是i,石头子集可以凑成的最大和
2、确定递推公式,典型背包公式递推,dp[j]=max(dp[j],dp[j-stones[i]]+stones[i])——一维,滚动数组
3、dp数组初始化,dp[0]=0
4、确定遍历顺序,双层for循环遍历,i从0到stones.length(遍历所有石头),j从sum/2到当前物品的重量stones[i]
5、举例推导dp数组
6、最后dp[target]是第一堆石头的重量和,则sum-dp[target]是另一堆石头的和,因为sum/2是向下取整的,所以第二堆石头重量肯定大于第一堆,所以返回sum-dp[target]-dp[target]
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for(int i = 0;i < stones.length;i++){
sum += stones[i];
}
int target = sum / 2;
int[] dp = new int[15001];
dp[0] = 0;
for(int i = 0;i < stones.length;i++){
for(int j = target;j >= stones[i];j--){
dp[j] = Math.max(dp[j],dp[j-stones[i]] + stones[i]);
}
}
return sum - dp[target] - dp[target];
}
}