【leetcode 494目标和】题解

494. 目标和 - 力扣(LeetCode)
https://leetcode.cn/problems/target-sum/

题解

写动规最重要的应该就是找出递推方程,感觉一般弄明白了递推方程的含义、形式,基本都能做出来了。这道题和背包问题很像,背包问题的递推方程是:

F\left ( i,C \right )=max(F((i-1),C),(F((i-1),C-w[i])+v[i]))

F(i,C)代表装第i个物品且背包此时最大容量为C时的最大价值。

而这里要求的是表达式的数目,大致可以猜到递推公式应代表将第i个数字放入表达式时,表达式之和为C的表达式次数。所以i代表数组中数字的索引,C代表还未放入第i个数字时,表达式的和。最终的结果应为F(n-1,targret),n为nums长度,target为目标和。而递推公式应该为:

dp[i][j]=dp[i-1][j-nums[i]]+dp[i-1][j+nums[i]]

但事实上并不是这么简单,因为题中涉及加数或者减数,所以dp数组的列数并不像背包问题一样,是背包最大容量,此题中即0~sum(nums数字总和sum),而应该是sum*2+1,从-sum,-sum+1,-sum+2一直到sum,因为它的最小值可以到-sum,即所有数字前都是负号。

另外还需要注意的是nums[i]等于0的情况,nums[i]==0时,初始化dp数组第一行时dp[0][i]就不是1,而是2,毕竟+0和-0都是0,有两种表达方式。

其他的问题就是要注意数组越界,以及表达式数目为0的情况。我踩到的坑就是这些啦~

代码

public int findTargetSumWays(int[] nums, int target) {
        int sum=0;
        int n=nums.length;
        for(int i=0;i<n;i++){
            sum+=nums[i];
        }
        int[][] dp=new int[n][sum*2+1];

        for(int i=0;i<(sum*2+1);i++){
            if((nums[0]==i-sum)||(nums[0]==sum-i)){
                if(nums[0]==0){
                    dp[0][i]=2;
                }
                else{
                    dp[0][i]=1;
                }
                
            }
        }

        for(int i=1;i<n;i++){
            for(int j=0;j<(sum*2+1);j++){
                if(j-nums[i]<0){
                    dp[i][j]=dp[i-1][j+nums[i]];
                }
                else if(j+nums[i]>sum*2){
                    dp[i][j]=dp[i-1][j-nums[i]];
                }
                else{
                    dp[i][j]=dp[i-1][j-nums[i]]+dp[i-1][j+nums[i]];
                }   
            }
        }

        if(target+sum>=sum*2+1||target<(-sum)){
            return 0;
        }
        else{
            return dp[n-1][target+sum];
        }
        
    }

写题感受

一道神奇(坑很多)的动态规划~

一开始看到就感觉应该是动规,但是想了一会儿没想出来递推方程应该怎么写,果断转向题解区(给动规大佬端茶doge),但是当天挺晚了就没仔细看,去睡觉了(熬夜达咩)。第二天开始认真写题,刚开始看题解就看到了熟悉又陌生的名词——背包问题,毅然决然转向CSDN先复习了一下背包问题,再回过来继续写这道题,然后慢慢改终于AC了~(仿佛又明白了一点动规的奥妙)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值