494. Target Sum

来源:互联网 发布:知乎手机版怎么收藏 编辑:程序博客网 时间:2024/06/11 18:18

You are given a list of non-negative integers, a1, a2, …, an, and a target, S. Now you have 2 symbols + and -. For each integer, you should choose one from + and - as its new symbol.

Find out how many ways to assign symbols to make sum of integers equal to target 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.
Note:
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.

该题是一道meduim的题,但是刚看到题意,立马有了回溯遍历的,但是细想,不可能会这么简单吧,但还是写了一下回溯的代码如下:

void dfs_Target(vector<int>& nums, int target, int pos, int subsum,int &count){    if (pos == nums.size()){        if (subsum == target)count++;        return;    }    dfs_Target(nums, target, pos + 1, subsum + nums[pos], count);    dfs_Target(nums, target, pos + 1, subsum - nums[pos], count);}int findTargetSumWays(vector<int>& nums, int S) {    if (nums.size() == 0)return 0;    int count = 0;    dfs_Target(nums, S, 0, 0, count);    return count;}

私以为这样的时间复杂度很高,测试一下虽然过了,但是只超过16.7%的算法

细想有没有其他的算法能够解决此问题,冥思苦想一会不得其解,故上网上了看了一下别人的代码,果然有妙计,还要什么电视机。。。

int findTargetSumWays(vector<int>& nums, int S) {    if (nums.size() == 0)return 0;    unordered_map<int, int> dp;    dp[0] = 1;    for (auto num : nums){        unordered_map<int, int> temp;        for (auto x : dp){            int sum = x.first, count = x.second;            temp[sum + num] += count;            temp[sum - num] += count;        }        dp = temp;    }    return dp[S];}

这样用了两个map,第一个map一直保持键值和键值和所对应的出现的次数,第二个map一直在循环中作为中间变量;

【问题分析】

1、该问题求解数组中数字只和等于目标值的方案个数,每个数字的符号可以为正或负(减整数等于加负数)。

2、该问题和矩阵链乘很相似,是典型的动态规划问题

3、举例说明: nums = {1,2,3,4,5}, target=3, 一种可行的方案是+1-2+3-4+5 = 3

 该方案中数组元素可以分为两组,一组是数字符号为正(P={1,3,5}),另一组数字符号为负(N={2,4}) 因此:    sum(1,3,5) - sum(2,4) = target          sum(1,3,5) - sum(2,4) + sum(1,3,5) + sum(2,4) = target + sum(1,3,5) + sum(2,4)          2sum(1,3,5) = target + sum(1,3,5) + sum(2,4)          2sum(P) = target + sum(nums)          sum(P) = (target + sum(nums)) / 2 由于target和sum(nums)是固定值,因此原始问题转化为求解nums中子集的和等于sum(P)的方案个数问题

4、求解nums中子集合只和为sum(P)的方案个数(nums中所有元素都是非负)

int subsetSum(vector<int>& nums, int s){    vector<int> dp(s + 1, 0);    dp[0] = 1;    for (auto num : nums){        for (int i = s; i >= num; i--){            dp[i] += dp[i - num];        }    }    return dp[s];}int findTargetSumWays(vector<int>& nums, int S) {    int sum = 0;    for (auto x : nums)sum += x;    return sum < S || (S + sum) & 1 ? 0 : subsetSum(nums, (S + sum) >> 1);}
原创粉丝点击