494. Objective and (DP)

Given an array of non-negative integers, a1, a2, …, an, and a target number, S. Now you have two symbols + and -. For any integer in the array, you can choose a symbol from + or-and add it in front.

Returns the number of methods that can make the final array and add symbols to the target number S.

Example:

Input: nums: [1, 1, 1, 1, 1], S: 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 make the final goal sum to 3.

analysis:

For dynamic programming, the problem is transformed into a 0-1 knapsack problem, and the target S is transformed into a problem of how to load items with different volumes in the knapsack. The recurrence formula is d[j] = d[j] + d[j-nums[i] ], traverse from back to front, to ensure that each item (nums[j]) is used only once, taking {1,1,1,1,1} as an example, draw the state transition table as shown below

Insert picture description here

public:
    int findTargetSumWays(vector<int>& nums, int S) {
    
    
        int wayTimes = 0;
        int sum = 0;
        for(int i = 0; i < nums.size(); i++) sum += nums[i];
        if (S > sum) return 0; // sum全为正数组成也无法找到S
        // 我们假设P是正子集,N是负子集 
        // 例如: 假设nums = [1, 2, 3, 4, 5],target = 3,
        // 一个可能的解决方案是+1-2+3-4+5 = 3 这里正子集P = [1, 3, 5]和负子集N = [2, 4]
        // 满足 x - (sum - x) = S => x = (S + sum) / 2
        // 推导: 假设加法的总和为x,那么减法对应的总和就是sum - x
        if ((S + sum) % 2 == 1) return 0; 
        int bagSize = (S + sum) / 2;
        vector<int> dp(bagSize + 1, 0);
        dp[0] = 1;
        for(int i = 0; i < nums.size(); i++){
    
    
            for(int j = bagSize; j >= nums[i]; j--){
    
    
                dp[j] += dp[j - nums[i]];
            }
        }
        for(int x : dp) cout << x <<" "; 
    
        return dp[bagSize];
    }

Insert picture description here

Guess you like

Origin blog.csdn.net/qq_34612223/article/details/113868860
DP