zoukankan      html  css  js  c++  java
  • 494. Target Sum

    问题:

    给定一组非负整数nums,和一个目标数S,求给nums的各个元素添加符号后,使得和为S的可能性有多少?

    Example 1:
    Input: nums is [1, 1, 1, 1, 1], S is 3. 
    Output: 5
    Explanation: 
    -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
    There are 5 ways to assign symbols to make the sum of nums be target 3.
     
    Constraints:
    The length of the given array is positive and will not exceed 20.
    The sum of elements in the given array will not exceed 1000.
    Your output answer is guaranteed to be fitted in a 32-bit integer.
    

      

    解法:DP(动态规划) 0-1 knapsack problem(0-1背包问题)

    首先,由于S的符号不确定,我们可以将问题转换为:

    ●将数组分为正数组和负数组,使得正数组的和为一个定值的可能性有多少种?

    推导:

    sum(P) - sum(N) = target
    sum(P) + sum(N) + sum(P) - sum(N) = target + sum(P) + sum(N)
                           2 * sum(P) = target + sum(nums)

    所以:sum(P) = (target + sum(nums)) / 2

    因此,计算正数组和sum(P),由上式,首先排除奇数结果

    if (target + sum(nums))%2==1 then return 0

    由于本题数位限制,int可能不足->

    if (target ^ sum(nums))&1==1 then return 0

    另外,若给数组全部赋正号或全部赋负号,

    S不能>sum(nums) , S不能<-sum(nums) 

    因此有:

    if((newsum^S)&1 || S>newsum || S<-newsum) return 0;

    接下来,对●问题的DP进行分析:

    1.确定【状态】:

    • 可选择的数:前 i 个数
    • 和:s:0~newsum

    2.确定【选择】:

    • 选择当前的数nums[i]
    • 不选择当前的数nums[i]

    3. dp[i][s]的含义:

    前 i 个数中,组成和=s 的可能性的个数。

    4. 状态转移:

    dp[i][s]= SUM {

    • 选择 nums[i]:dp[i-1][s-nums[i]]:=前 i-1 个元素可组成和为 s-nums[i] 的可能性个数
    • 不选择 nums[i]:dp[i-1][s]:=前 i-1 个元素可组成和为 s 的可能性个数

    }

    5. base case:

    • dp[0][s]=false
    • dp[i][0]=true
    • dp[0][0]=true

    ♻️ 优化:去掉 i ,

    将s倒序。

    代码参考:

     1 class Solution {
     2 public:
     3     //Eq1:Positive+Negative=sum
     4     //Eq2:Positive-Negative=S
     5     //Eq1+Eq2:2*Positive=sum+S
     6     //Positive=(sum+S)/2
     7     //to find S-> to find subset which sum=Positive
     8     
     9     
    10     //dp[i][s]: in first i items, the number of ways whose sum is s
    11     //case_1,choose i-th item: dp[i-1][s-val[i]]
    12     //case_2,don't choose: dp[i-1][s]
    13     //dp[i][s] = case_1 + case_2
    14     //base case: dp[0][s] = 0
    15     //dp[i][0] = 1
    16     //dp[0][0] = 1
    17     //
    18     int findTargetSumWays(vector<int>& nums, int S) {
    19         int newsum = 0;
    20         for(int n:nums){
    21             newsum+=n;
    22         }
    23         if((newsum^S)&1 || S>newsum || S<-newsum) return 0;
    24         newsum = (newsum+S)/2;
    25         vector<int> dp(newsum+1, 0);
    26         dp[0]=1;
    27         for(int i=1; i<=nums.size(); i++) {
    28             for(int s=newsum; s>=0; s--) {
    29                 if(s-nums[i-1]>=0) {
    30                     dp[s] += dp[s-nums[i-1]];
    31                 }
    32             }
    33         }
    34         return dp[newsum];
    35     }
    36 };
  • 相关阅读:
    sys、os 模块
    sh 了解
    TCP协议的3次握手与4次挥手过程详解
    python argparse(参数解析)模块学习(二)
    python argparse(参数解析)模块学习(一)
    Day17--Python--面向对象--成员
    Day16--Python--初识面向对象
    Day14--Python--函数二,lambda,sorted,filter,map,递归,二分法
    Day013--Python--内置函数一
    Day12--Python--生成器,生成器函数,推导式,生成器表达式
  • 原文地址:https://www.cnblogs.com/habibah-chang/p/13582908.html
Copyright © 2011-2022 走看看