Day38:LeedCode 1049. 最后一块石头的重量 II 494. 目标和 474.一和零

1049. 最后一块石头的重量 II

有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。

每一回合,从中选出任意两块石头 ,然后将它们一起粉碎。假设石头的重量分别为 xy,且 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

提示:

  • 1 <= stones.length <= 30
  • 1 <= stones[i] <= 100

思路:本题和Day42:动态规划 LeedCode 01背包 416. 分割等和子集-CSDN博客

中的分割等和子集类似,其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就化解成01背包问题了

动态规划:

1.确定dp数组以及下标的含义

dp[i]:容量为i的背包,能背的最大重量

相对于 01背包,本题中,石头的重量是 stones[i],石头的价值也是 stones[i]

2.确定递推公式

dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);

3.dp数组如何初始化

dp[j]都初始化为0

4.确定遍历顺序

如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历

最后dp[target]里是容量为target的背包所能背的最大重量。

5.举例推导

复制代码
class Solution {
    public int lastStoneWeightII(int[] stones) {
   int length=stones.length;
   int target=0;
   int sums=0;
   for(int i=0;i<stones.length;i++){
    sums+=stones[i];
   }
   target=sums/2;
   int[] dp=new int[target+1];
   for(int i=0;i<length;i++){
    for(int j=target;j>=0;j--){
        if(j>=stones[i]){
            dp[j]=Math.max(dp[j],dp[j-stones[i]]+stones[i]);
        }
    }
   }
   return sums-dp[target]-dp[target];
    }
}

注意:在计算target的时候,target = sum / 2 因为是向下取整,所以sum - dptarget 一定是大于等于dptarget


494. 目标和

给你一个非负整数数组 nums 和一个整数 target

向数组中的每个整数前添加 '+''-' ,然后串联起所有整数,可以构造一个 表达式

  • 例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1"

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例 1:

复制代码
输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 3 。
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3

示例 2:

复制代码
输入:nums = [1], target = 1
输出:1

提示:

  • 1 <= nums.length <= 20
  • 0 <= nums[i] <= 1000
  • 0 <= sum(nums[i]) <= 1000
  • -1000 <= target <= 1000

思路:

假设加法的总和为x,那么减法对应的总和就是sum - x。

所以我们要求的是 x - (sum - x) = target

x = (target + sum) / 2

此时问题就转化为,装满容量为x的背包,有几种方法。

由于数组中的数都是整数,所以加法总和x一定是整数,如果(target + sum) / 2不是整数,意味着无解,return 0

与此同时,如果target的绝对值已经大于sum,那么也是没有方案的。

动态规划:

1.确定dp数组以及下标的含义

dp[i][j] 表示:用[0,i]的数,填满j(包括j)这么大容积的包,有dp[i][j]种方法

2.确定递推公式

得到nums[i],凑成dpij就有dpi-1j-nums\[i] 种方法。

没有用到nums[i],凑出凑成dpij就有dpi-1j种方法。

故:dpij=dpi-1j+dpi-1j-nums\[i];

3.dp数组如何初始化

nums[i]!=0时:在初始化的时候dp[i][0]一定要初始化为1,凑出和为0的有1种方法

numsi==0时:在初始化的时候dp[i][0]一定要初始化为1,凑出和为0的有2种方法

4.确定遍历顺序

dpij=dpi-1j+dpi-1j-nums\[i];由递推公式可知从上往下遍历

5.举例推导

代码参考:

二维数组

复制代码
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
    int sums=0;
    for(int i=0;i<nums.length;i++){
        sums+=nums[i];
    }
    int x=(sums+target)/2;
    if((sums+target)%2==1)return 0;
    if(Math.abs(target)>sums) return 0;
    int[][] dp=new int[nums.length][x+1];
    //初始化
    for(int i=0;i<nums.length;i++){
        dp[i][0]=1;
    }
     for(int i=0;i<=x;i++){
        if(i==nums[0]){
           dp[0][i]+=1;
        }
     }
    for(int i=1;i<nums.length;i++){
        for(int j=0;j<=x;j++){
          if(j>=nums[i]){
            dp[i][j]=dp[i-1][j]+dp[i-1][j-nums[i]];}
            else{
                dp[i][j]=dp[i-1][j];
            }
        }
    }
    return dp[nums.length-1][x];
    }
}

一维数组:

复制代码
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
    int sums=0;
    for(int i=0;i<nums.length;i++){
        sums+=nums[i];
    }
    int x=(sums+target)/2;
    if((sums+target)%2==1)return 0;
    if(Math.abs(target)>sums) return 0;
    int[] dp=new int[x+1];
    //初始化
     dp[0]=1;
    for(int i=0;i<nums.length;i++){
        for(int j=x;j>=nums[i];j--){
            dp[j]=dp[j]+dp[j-nums[i]];  
        }
    }
    return dp[x];
    }
}
相关推荐
测试仪器廖生1359025638519 分钟前
罗德与施瓦茨 FSP13频谱分析仪FSP30
网络·人工智能·算法
happymaker062621 分钟前
LeetCodeHot100——560.和为K的子数组
算法
dtq042438 分钟前
C语言刷题数组5,6(求平均值,求最大值)
c语言·数据结构·算法
郭梧悠1 小时前
Hash算法入门Hash冲突解决方案
算法·哈希算法
洛水水1 小时前
【力扣100题】81.寻找两个正序数组的中位数
数据结构·算法·leetcode
happymaker06262 小时前
LeetCodeHot100——155.最小栈
算法
洛水水2 小时前
【力扣100题】85.每日温度
算法·leetcode·职场和发展
Coder-magician2 小时前
《代码随想录》刷题打卡day15:二叉树part05
数据结构·c++·算法
Kurisu_红莉栖2 小时前
力扣56合并区间
算法·leetcode
Irissgwe2 小时前
算法的时间复杂度和空间复杂度
数据结构·c++·算法·c·时间复杂度·空间复杂度