LeetCode 494. 目标和【java】

LeetCode 494. 目标和【java】

给你一个整数数组 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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/target-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解如下:

泪目了 家人们,刚开始学DP 记忆化递归这么好写的题目DP竟然这么恶心。。。。

dp[i][j] 代表什么?代表的是nums中第i个数字 能凑成j的方法数量

首先拿到题先找状态转移方程,每次不是+ 就是 - 所以 dp[i][j] = dp[i-1][j+nums[i]]+dp[i-1][j-nums[i]]

这个还是不难想出来的,我们要求的值一定是 加 和减 两种方法之和

那么问题来了 我们怎么定义dp[][]的范围,下标是没有负数的,这里我们用一个巧妙地办法 就是全部右移sum个 sum是nintums数组的全部值加起来

那么int[][] dp = new int[nums.length][2*sum+1];如图 1就是多出来的0 两倍的范围 从-sum,sum的的取值范围,其实-5就是0,5就是2sum

在这里插入图片描述

base case是什么呢?即初始化值,看状态转移方程 ,dp[i][j] = dp[i-1][j+nums[i]]+dp[i-1][j-nums[i]] 所以可以知道是从图中红色的两个数据相加 得到的

注意,0的位置其实是sum的位置,那么图中看到的位置是 0-nums[0]和0+nums[0]

dp[0][sum-nums[0]] = 1;

dp[0][sum+nums[0]] = 1;

那么在计算的过程中,我们会发现有越界问题,就是sum +/- nums 会越界!就是小于0位置的 -sum 和大于 5位置的sum

所以加一个判断 j-nums[i] >0 就还是继续减,一旦小于等于 0 就直接等于0

j+nums[i] < 2*sum+1 也判断一下 小于就继续加,大于等于就直接等于0

public class _494目标和 {
    public static void main(String[] args) {
        int[] a = {1,1,1,1,1};
        new _494目标和().findTargetSumWays(a,3);
    }
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for(int num : nums){
            sum += num;
        }
        if(Math.abs(target) > Math.abs(sum)) return 0;
        int[][] dp = new int[nums.length][2*sum+1];
        dp[0][sum-nums[0]] =1;
        dp[0][sum+nums[0]] =1;
        for(int i = 1;i<nums.length;i++){
            for(int j = sum; j<= 2*sum+1 ; j++){
                int d1 = j+nums[i] <sum?j+nums[i]:0;
                int d2 = j-nums[i] >-sum?j-nums[i]:0;
                dp[i][j] =dp[i-1][d1]+dp[i-1][d2];
            }
        }
        return dp[nums.length-1][sum+target];
    }
}

共同学习,共同进步

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值