「这是我参与2022首次更文挑战的第39天,活动详情查看:2022首次更文挑战」。
最后一块石头的重量
题目描述
有一堆石头,用整数数组stones
表示。其中stones[i]
表示第i块石头的重量。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别位x
和y
,且x<=y
。那么粉碎的可能结果如下:
如果x==y
,那么两块石头都会被完全粉碎。
如果x!=y
,那么重量为x
的石头将会完全粉碎,而重量为y的石头新重量为y-x
。
最后,最多只剩下一块石头。返回此石头最小的可能重量。如果没有石头剩下,就返回0
。
示例1:
输入: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],这就是最优值。
示例2:
输入: stones = [31,26,33,21,40]
输出: 5
示例3:
输入: stones = [1,2]
输出: 1
算法解析
这道题目实质上就是01背包问题的一个变换,这里的stones[i]就是weight[i],同时也是value[j]。 关于01背包问题,我们可以参照01背包问题的递推公式然后推出本题的递推公式。
dp[i][j]表示从下标为0到j的物品里任意取,放进容量为j的背包,价值总和最大是多少。
weight[i]表示第i个物品的重量,value[i]表示第i个物品的价值
由此我们可以推出本题的递推公式为
这里的背包容量是所有石头的重量之和sum/2,在这里我们以示例1为例,画出二维数组
stones[i]=[2,7,4,1,8,1],target=(2+7+4+1+8+1)/2=11
由递推公式得
dp[0][0]=0,dp[1][0]=0,dp[2][0]=0,dp[3][0]=0,dp[4][0]=0,dp[5][0]=0
dp[0][1]=0,
dp[1][1]=dp[0][1]=0,
dp[2][1]=dp[1][1]=0,
dp[3][1]=max{dp[2][1],dp[2][1-1]+1}=max(0,1)=1,
dp[4][1]=dp[3][1]=1,
dp[5][1]=max{dp[4][1],dp[4][1-1]+1}=max(1,1)=1,
dp[0][2]=max{dp[-1][2],dp[-1][2-1]+2}=max(0,2)=2,
dp[1][2]=dp[0][2]=2,
dp[2][2]=dp[1][2]=2,
dp[3][2]=max{dp[2][2],dp[2][2-1]+1}=max{2,1}=2,
dp[4][2]=dp[3][2]=2,
dp[5][2]=max{dp[4][2],dp[4][2-1]+1}=max{2,2}=2.
dp[0][3]=max{dp[-1][3],dp[-1][3-2]+2}=max(0,2)=2,
dp[1][3]=dp[0][3]=2,
dp[2][3]=dp[1][3]=2,
dp[3][3]=max{dp[2][3],dp[2][2]+1}=max{2,3}=3,
dp[4][3]=dp[3][3]=3,
dp[5][3]=max{dp[4][3],dp[4][2]+1}=max{3,3}=3,
dp[0][4]=max{dp[-1][4],dp[-1][2]+2}=max{0,2}=2,
dp[1][4]=dp[0][4]=2,
dp[2][4]=max{dp[1][4],dp[1][0]+4}=max{2,4}=4,
dp[3][4]=max{dp[2][4],dp[2][3]+1}={4,3}=4,
dp[4][4]=dp[3][4]=4,
dp[5][4]=max{dp[4][4],dp[4][3]+1}=max{4,4}=4
因为递推过多这里就不多加赘述了,计算好之后绘制表格如下
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
2 | 0 | 0 | 2 | 2 | 2 | 2 | 2 | 7 | 7 | 9 | 9 |
3 | 0 | 0 | 2 | 2 | 4 | 4 | 6 | 7 | 7 | 9 | 9 |
4 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
5 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
6 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
代码解析
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum=0;
for(int i=0;i<stones.length;i++){
sum+=stones[i];
}
//求出target
int target=sum/2;
//定义dp数组
int[][] dp=new int[stones.length][target+1];
for(int j=stones[0];j<=target;j++){
dp[0][j]=stones[0];
}
//递推公式
for(int i=1;i<stones.length;i++){
for(int j=1;j<=target;j++){
if(j>=stones[i]){
dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-stones[i]]+stones[i]);
}else{
dp[i][j]=dp[i-1][j];
}
}
}
return (sum-dp[stones.length-1][target])-dp[stones.length-1][target];
}
}