494-目标和(01背包)

这是一篇关于如何使用动态规划解决LeetCode中的目标和(01背包)问题的博客。文章提供了两种解题思路,一种是通过构建二叉树来解决,另一种是直接应用动态规划。在动态规划的解决方案中,作者详细解释了如何将问题转化为01背包问题,并给出了时间复杂度和空间复杂度的分析。通过特例判断和状态转移方程,作者展示了如何构建动态规划数组以找到满足目标和的方案数。
摘要由CSDN通过智能技术生成

题目

给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。

返回可以使最终数组和为目标数 S 的所有添加符号的方法数。

示例:

输入:nums: [1, 1, 1, 1, 1], S: 3
输出:5
解释:

-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

一共有5种方法让最终目标和为3。

题解一(二叉树)

class Solution {
    int count=0;
    public int findTargetSumWays(int[] nums, int target) {
        dfs(nums,target,0);
        return count;
    }
    public void dfs(int[] nums,int target,int i){
        //i是用来记录循环次数和i所在的位置的nums数组值的
        if(i==nums.length&&target==0){
            count++;
            return;
        }
        if(i<nums.length){
            dfs(nums,target-nums[i],i+1);//注意:循环调用只能用+1!不能用++,栈会溢出!原因不明?
            dfs(nums,target+nums[i],i+1);
        }
    }
}

思路:

  1. 二叉树:

                        0
            -1           +1      
      -1    +1    -1       +1
       .......            ......        ...
    

题解二(dp)

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum=0;
        for(int num:nums){
            sum+=num;
        }
        if(target>sum||(sum+target)%2==1){
            return 0;
        }
        int newTarget=(sum+target)/2;
        int[] dp=new int[newTarget+1];
        dp[0]=1;
        for(int num:nums){
            for(int j=newTarget;j>=num;j--){
                dp[j]=dp[j]+dp[j-num];
            }
        }
        return dp[newTarget];
    }
}

思路:

  1. 复杂度分析

    • 时间复杂度:O(n * target)O(ntarge**t)
    • 空间复杂度:O(target)O(targe**t)
  2. 思路

    • 01背包问题是选或者不选,但本题是必须选,是选+还是选-。先将本问题转换为01背包问题。
    • 假设所有符号为+的元素和为x,符号为-的元素和的绝对值是y。
      我们想要的 S = 正数和 - 负数和 = x - y
      而已知x与y的和是数组总和:x + y = sum
      可以求出 x = (S + sum) / 2 = target
      也就是我们要从nums数组里选出几个数,令其和为target
      于是就转化成了求容量为target的01背包问题 =>要装满容量为target的背包,有几种方案
    • 特例判断
      如果S大于sum,不可能实现,返回0
      如果x不是整数,也就是S + sum不是偶数,不可能实现,返回0
    • dp[j]代表的意义:填满容量为j的背包,有dp[j]种方法。因为填满容量为0的背包有且只有一种方法,所以dp[0] = 1
    • 状态转移:dp[j] = dp[j] + dp[j - num],
      当前填满容量为j的包的方法数 = 之前填满容量为j的包的方法数 + 之前填满容量为j - num的包的方法数
      也就是当前数num的加入,可以把之前和为j - num的方法数加入进来。
    • 返回dp[-1],也就是dp[target]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

codrab

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值