leetcode 494. 目标和

https://leetcode-cn.com/problems/target-sum/

 枚举dfs。两个优化:

记录当前的位置和计算数字。

1.记录后缀和,利用当前的计算数字,可以计算出最终结果的最大和最小范围,如果目标值不在这个范围内,则可以剪枝。

2.记录状态结果。

 

class Solution {
public:
    vector nums;
    int target;
    int ans;
    int n;
    vector post_sum;
    int dp[25][2005];
    int offset=1000;

    void dfs(int i,int sum){
        if(i==n ){
            if(sum==target)
                ans++;
            return;
        }

        if(dp[i][sum+offset]!=-1){
            ans+=dp[i][sum+offset];
            return;
        }

        if(sum+post_sum[i]target)
            return;

        int old_ans=ans;

        dfs(i+1,sum-nums[i]);
        dfs(i+1,sum+nums[i]);

        int delta=ans-old_ans;
        dp[i][sum+offset]=delta;

    }

    int findTargetSumWays(vector& nums_, int S) {
        nums=nums_;
        n=nums.size();
        target=S;
        ans=0;
        memset(dp,-1,sizeof(dp));
        post_sum=vector(n,0);
        post_sum[n-1]=nums[n-1];
        for(int i=n-2;i>=0;i--){
            post_sum[i]=post_sum[i+1]+nums[i];
        }

        dfs(0,0);
        return ans;
    }
};

 

动态规划版本

由于可能有负数,加上一个offset。

判断访问数字是否在范围内。

输入的target可能不在1000范围内。

class Solution {
public:
    vector nums;
    int target;
    int ans;
    int n;
    int dp[25][2005];
    int offset=1000;

    

    int findTargetSumWays(vector& nums_, int S) {
        nums=nums_;
        n=nums.size();
        target=S;
        ans=0;
        memset(dp,0,sizeof(dp));

        dp[0][nums[0]+offset]=1;
        dp[0][-nums[0]+offset]+=1;

        for(int i=1;i=-1000 && sum+nums[i]<=1000)
                    dp[i][sum+offset]+=dp[i-1][sum+nums[i]+offset];

                if(sum-nums[i]>=-1000 && sum-nums[i]<=1000){
                    dp[i][sum+offset]+=dp[i-1][sum-nums[i]+offset];
                }
            }
        }
      
        if(target>=-1000 && target<=1000)
            return dp[n-1][target+offset];
        return 0;
    }
};

 

你可能感兴趣的:(LeetCode)