zoukankan      html  css  js  c++  java
  • 494. 目标和(动态规划,01背包)

    给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。

    返回可以使最终数组和为目标数 S 的所有添加符号的方法数。

    示例:

    输入:nums: [1, 1, 1, 1, 1], S: 3
    输出:5
    解释:

    -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

    一共有5种方法让最终目标和为3。
     

    提示:

    数组非空,且长度不会超过 20 。
    初始的数组的和不会超过 1000 。
    保证返回的最终结果能被 32 位整数存下。
    通过次数55,907提交次数125,631

    回溯超时:

    class Solution {
    public:
        
        void backtrace(int sum,int S,vector<int>& nums,int pos) {
            //符合条件直接添加返回
            if(sum == S && pos == nums.size()){
                result++;
                return;
            }
            if(pos >= nums.size()) return;
             //第i个数取+
            sum += nums[pos];
            backtrace(sum,S,nums,pos+1);
            sum -= nums[pos];
               
            //第i个数取-
            sum -= nums[pos];
            backtrace(sum,S,nums,pos+1);
            sum += nums[pos];
            
        }
        int findTargetSumWays(vector<int>& nums, int S) {
            backtrace(0,S,nums,0);
            return result;
        }
    public:
        int result = 0;
    };

    dp:要转化成dp

    class Solution {
    public:
        //dp系列:01背包
        //dp[i][j] = dp[i-1][j-nums[i]] + dp[i-1][j+nums[i]] 这种dp转移相对麻烦一些
        //另一种想法:数组分为正负两部分.   例如1 3 5 为加 sum(P)  2 4为- sum(N)
        //sum(P) + sum(N) = S
        //sum(P) - sum(N) = sum(nums)
        //sum(P) - sum(N) + sum(P) + sum(N) = S + sum(nums) ==> 2*sum(P) = s+sum(nums) ==> sum(P) = (S+sum(nums))/2
        //典型的01背包,从nums中取 k个数使得和P 为(S+sum(nums))/2
        int findTargetSumWays(vector<int>& nums, int S) {
            int n = nums.size();
            int sum = accumulate(nums.begin(),nums.end(),0);
            long s = long(sum) + long(S);
            if(s % 2 || sum < S) return 0;
            vector<vector<int>> dp(n+1,vector<int>(s/2+1,0));
            for(int i=1;i<=n;i++){
                dp[i][0] = 1;
            }
            for(int j=1;j<=s/2;j++){
                dp[0][j] = 0;
            }
            dp[0][0] = 1;
            for(int i=1;i<=n;i++){
           //j从0开始,否则 dp[1][0]对于某些情况失败,[0 0 1] 1中dp[1][0] = 2
    for(int j=0;j<=s/2;j++){ if(j >= nums[i-1]) dp[i][j] = dp[i-1][j]+dp[i-1][j-nums[i-1]]; else dp[i][j] = dp[i-1][j]; } } return dp[n][s/2]; } };
  • 相关阅读:
    [刷题] IDA*
    [BZOJ1330] Editing a Book
    [BZOJ5449] 序列
    [刷题] 搜索剪枝技巧
    [XJOI3529] 左右
    [CF920E] Connected Components?
    [第18届 科大讯飞杯 J] 能到达吗
    洛谷 P4779 【模板】单源最短路径(标准版)
    洛谷 P1175 表达式的转换
    pipioj 1291 中缀表达式转后缀表达式I
  • 原文地址:https://www.cnblogs.com/wsw-seu/p/14163609.html
Copyright © 2011-2022 走看看