力扣494题:目标和

力扣494题:目标和

题目描述

给你一个整数数组 nums 和一个整数 target 。

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

例如,nums = [2, 1] ,可以在 2 之前添加 ‘+’ ,在 1 之前添加 ‘-’ ,然后串联起来得到表达式 “+2-1” 。
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

输入输出样例

输入: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

输入:nums = [1], target = 1
输出:1

解法一:使用递归实现

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

    //count,表明当前的字符串的长度
    //curr,表明该路径遍历结点的值

    int dfs(vector<int>nums,int target,int count,int curr)
    {
        //判断递归终止条件
        if(count==nums.size())
        {
            return curr==target?1:0;
        }
        int left=dfs(nums,target,count+1,curr+nums[count]);
        int right=dfs(nums,target,count+1,curr-nums[count]);
        return left+right;
    }
};

解法二:使用记忆化搜索

//使用记忆化搜素的思想,在hash表中将路径结点与出现的次数进行保存
class Solution2{
public:
    unordered_map<string,int>maps;
    int findTargetSumWays(vector<int>&nums,int target)
    {
        return dfs(nums,target,0,0);
    }

    //count,表明当前的字符串的长度
    //curr,表明该路径遍历结点的值

    int dfs(vector<int>nums,int target,int count,int curr)
    {
        string key=to_string(count)+"_"+to_string(curr);
        if(maps.count(key))
        {   
            return maps[key];
        }
        //判断递归终止条件
        if(count==nums.size())
        {
            return curr==target?1:0;
        }
        int left=dfs(nums,target,count+1,curr+nums[count]);
        int right=dfs(nums,target,count+1,curr-nums[count]);
        maps[key]=left+right;

        return maps[key];
    }
};

解法三,使用动态规划

//使用动态规划,将原问题转换成0-1背包问题
//因为符号不仅只有+号还有-号,因此长度要为2*sum+1
//只考虑加法和减法操作,动态转移方程为
//dp[i][j]=dp[i-1][j-nums[i]]+dp[i-1][j+nums[i]]
class Solution3{
public:
    int findTargetSumWays(vector<int>&nums,int target)
    {
        if(nums.empty())
        {
            return 0;
        }

        int sum=0;
        //计算当前数组的总和
        for(auto i:nums)
        {
            sum+=i;
        }
        //如果绝对值的总和小于target目标值,则无论如何添加路径都无法实现
        if(abs(sum)<abs(target))
        {
            return 0;
        }

        int length=nums.size();
        //range,需要包含两边的sum,(正数和负数),还要加上0
        int range=2*sum+1;

        //建立动态规划的数组
        //数组需要从-sum开始进行实现
        vector<vector<int>>dp(length,vector<int>(range));

        //对动态规划数组进行初始化
        //由0-1背包问题可以得出,初始背包容量只有nums[0]可以满足
        dp[0][sum+nums[0]]+=1;
        dp[0][sum-nums[0]]+=1;

        //建立状态转移方程,设置边界条件
        for(int i=1;i<length;i++)
        {
            for(int j=-sum;j<=sum;j++)
            {
                //当坐标大于右边界,只需要考虑结果是减法的即可
                if((j+nums[i]>sum))
                {
                    dp[i][j+sum]=dp[i-1][j-nums[i]+sum];
                }
                //当坐标小于左边界,只需要考虑加法
                else if(j-nums[i]<-sum)
                {
                    dp[i][j+sum]=dp[i-1][j+nums[i]+sum];
                }
                else{
                    dp[i][j+sum]=dp[i-1][j-nums[i]+sum]+dp[i-1][j+nums[i]+sum];
                }
            }
        }
    return dp[length-1][sum+target];

    }

};

解法四:使用0-1背包实现

//动态规划,解法四
class Solution4{
public:
    int findTargetSumWays(vector<int>&nums,int target)
    {
        if(nums.empty())
        {
            return 0;
        }

        int sum=0;
        //计算当前数组的总和
        for(auto i:nums)
        {
            sum+=i;
        }

        int diff=sum-target;
        //使用动态规划的前提sum-target的结果是非负偶数
        if(diff<0||diff%2!=0)
        {
            return 0;
        }

        int length=nums.size();
        int neg=diff/2;

        //定义状态转移方程
        vector<vector<int>>dp(length+1,vector<int>(neg+1));
        //初始化dp数组
        dp[0][0]=1;

        //状态转移
        //先遍历物品
        for(int i=1;i<=length;i++)
        {
            //再遍历背包容量
            for(int j=0;j<=neg;j++)
            {
                dp[i][j]=dp[i-1][j];
                //如果背包剩余j的容量大于放的物品nums[i-1]
                //则可以将物品nums[i-1]放进背包中
                if(j>=nums[i-1])
                {
                    dp[i][j]+=dp[i-1][j-nums[i-1]];
                }
            }
        }
        return dp[length][neg];
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值