494. 目标和

在这里插入图片描述
这不妥妥的dfs吗。对每一位有两种情况+和-。一直到数组结尾再判断s是否等于0,如果等于0相当于有一种情况,res++。

class Solution {
public:
    void dfs(vector<int>& nums, int index, int S){
        if(index == nums.size()){
            if(S == 0) res++;
            return;
        }
        dfs(nums,index+1,S+nums[index]);
        dfs(nums,index+1,S-nums[index]);
        return;
    }
    int findTargetSumWays(vector<int>& nums, int S) {
        //dfsordp
        //dfs就是找一种可以实现的情况,dfs下一位两种情况,选或者不选,当遍历到最后一位了判断如果等于0就++并返回
        //有大量重复计算,有点像01背包  
        //直接排除全加小于或者全减大于
        int sum = 0, jian = 0;
        for(int x:nums){
            sum += x;
            jian -= x;
        }
        if(sum < S || jian > S) return 0;
        dfs(nums,0,S);
        return res;
    }
private:
    int res = 0;
};

可以dfs,但是时间复杂度比较高。
我们考虑dp,我们找一组正数和为left,一组负数和为-right
left-right = S。left+right = sum。left-(sum-left)=S->left = (S+sum)/2
所以我们只要找和为(sum+S)/2,dp[j]就是前i位数字能组成i的情况,因为只和左上有关,一维从后往前遍历即可

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int S) {
        int sum = 0;
        for(int x:nums){
            sum += x;
        }
        //left-right = S
        //left+right = sum
        //left-(sum-left)=S->left = (S+sum)/2
        if(sum <S || (sum+S)%2 ==1) return 0;
        int target = (sum+S)/2;
        vector<int> dp(target+1);
        //basecase:将装重量为0的背包设为1
        dp[0] = 1;
        //只和左上的状态有关系,一维从后往前遍历即可
        for(int i = 0; i < nums.size(); ++i){
            //防止越界控制j的大小
            for(int j = target; j >= nums[i]; --j){
                //只考虑正数
                dp[j] += dp[j-nums[i]];
            }
        }
        return dp[target];
    }
};

dfs或者记忆化递归,因为这里dfs爆搜也是会重复的,但是怎么样判断和前面搜索过的相同呢?这里不仅和index有关,也和tmp有关,我们将tmp和index相连形成一个string,这样就生成独一无二的key了,接下来就是简单的记忆化搜索了。

class Solution {
public:
    // void dfs(vector<int>& nums,int tmp, int index,int target){
    //     if(index == nums.size()){
    //         if(tmp == target) res++;
    //         return;
    //     }
    //     dfs(nums,tmp+nums[index],index+1,target);
    //     dfs(nums,tmp-nums[index],index+1,target);
    // }
    int dfs(vector<int>& nums,int target,int index, int tmp){
        string key = to_string(index) + "_" + to_string(tmp);
        if(ma.count(key)) return ma[key];
        if(index == nums.size()){
            ma[key] = (tmp == target?1:0);
            return ma[key];
        }
        int left = dfs(nums,target,index+1,tmp + nums[index]);
        int right = dfs(nums,target,index+1,tmp - nums[index]);
        ma[key] = left + right;
        return ma[key];
    }
    int findTargetSumWays(vector<int>& nums, int target) {
        //只有+或者-
        //dfs肯定超时,试试看,dfs可以过...
        // dfs(nums,0,0,target);
        // return res;

        return dfs(nums,target,0,0);
    }
private:
//     int res = 0;
    unordered_map<string,int> ma;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值