力扣 494. 目标和 爆搜 dp

62 篇文章 0 订阅
27 篇文章 0 订阅

https://leetcode-cn.com/problems/target-sum/
在这里插入图片描述
思路一:爆搜出奇迹。

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        return dfs(nums,0,target);
    }

    int dfs(const vector<int>&nums, int idx,int target)
    {
        if(idx==nums.size())
            return !target;
        return dfs(nums,idx+1,target+nums[idx])+dfs(nums,idx+1,target-nums[idx]);
    }
};

思路二:dp,先要对题目做一个转换。考虑数组元素之和为 s u m sum sum,假设挑选若干个元素使得它们前面的符号为负号,不妨设这些元素的和为 n e g neg neg,那么加上负号后其和就为 − n e g -neg neg,显然其余元素的和为 s u m − n e g sum-neg sumneg,由 ( s u m − n e g ) + ( − n e g ) = t a r g e t (sum-neg)+(-neg)=target (sumneg)+(neg)=target可得, n e g = ( s u m − t a r g e t ) / 2 neg=(sum-target)/2 neg=(sumtarget)/2。那么问题就可以转换为从数组中选任意个元素,使得它们的和为 n e g neg neg的方法数。是不是有点01背包的味道了?考虑 d p i dp_i dpi表示和为 i i i的方法数,显然对于第 j j j个数字,我们有:
d p k = d p k + d p k − n u m s j dp_k=dp_k+dp_{k-nums_j} dpk=dpk+dpknumsj
由于每个数字只能选一次(01背包),因此 k k k需要逆着推。

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int sum=0,n=nums.size();
        for(int i=0;i<n;i++)
            sum+=nums[i];
        sum-=target;
        if(sum<0||sum&1)
            return 0;
        target=sum>>1;
        vector<int> dp(target+1);
        dp[0]=1;
        for(int i=0;i<n;i++)
            for(int j=target;j>=nums[i];j--)
                dp[j]+=dp[j-nums[i]];
        return dp[target];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值