专栏首页Michael阿明学习之路LeetCode 494. 目标和(DFS+DP)

LeetCode 494. 目标和(DFS+DP)

1. 题目

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

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

示例 1:

输入: 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。

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/target-sum 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 解题

2.1 递归

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int S) {
    	int count = 0;
        bt(0,0,nums,S,count);
        return count;
    }
    void bt(int i, int cursum, vector<int>& nums, int &S, int &count) 
    {
    	if(i == nums.size())
    	{
    		if(cursum == S)
    			++count;
    		return;
    	}
    	bt(i+1,cursum+nums[i],nums,S,count);
    	bt(i+1,cursum-nums[i],nums,S,count);
    }
};

循环BFS,超时

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int S) {
    	int count = 0, n, lv = 0;
    	queue<int> q;
    	q.push(0);
    	while(!q.empty())
    	{
    		n = q.size();
    		while(n--)
    		{
    			if(lv == nums.size())
    			{
                    if(q.front()==S)
    				    ++count;
                    q.pop();
    			}
                else
                {
                    q.push(q.front()+nums[lv]);
                    q.push(q.front()-nums[lv]);
                    q.pop();
                }
    		}
    		lv++;
    	}
    	return count;
    }
};

2.2 DP

参考别人的 假设P是正子集,N是负子集 例如: 假设nums = [1, 2, 3, 4, 5],target = 3,一个可能的解决方案是+1-2+3-4+5 = 3 这里正子集P = [1, 3, 5]和负子集N = [2, 4]

如何将其转换为子集求和问题:

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

原来的问题转化为一个求子集的和问题: 找到nums的一个子集 P,使得sum( P ) = (target + sum(nums)) / 2,从上面最后个式子,可看出 target+sum(nums) 为偶数

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int S) {
        int i, j, sum_nums = 0;
        for(i = 0; i < nums.size(); ++i)
        	sum_nums += nums[i];
        if((long(sum_nums)+S)%2 != 0 || S > sum_nums)
        	return 0;
        S = (S+sum_nums)>>1;
        long *dp = new long [S+1];
        memset(dp,0,(S+1)*sizeof(long));
        dp[0] = 1;
        for(i = 0; i < nums.size(); ++i)
        {
        	for(j = S; j >= 0; --j)
        	{
        		if(dp[j] != 0 && j+nums[i] <= S)
        			dp[j+nums[i]] += dp[j];
        	}
        }
        return dp[S];
    }
};

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • LeetCode 666. 路径和 IV(树的遍历)

    给定一个包含三位整数的升序数组,表示一棵深度小于 5 的二叉树, 请你返回从根到所有叶子结点的路径之和。

    Michael阿明
  • LeetCode 259. 较小的三数之和(固定一点,内层双指针)

    给定一个长度为 n 的整数数组和一个目标值 target,寻找能够使条件 nums[i] + nums[j] + nums[k] < target 成立的三元组...

    Michael阿明
  • LeetCode 1403. 非递增顺序的最小子序列(排序)

    给你一个数组 nums,请你从中抽取一个子序列,满足该子序列的元素之和 严格 大于未包含在该子序列中的各元素之和。

    Michael阿明
  • Leetcode 1365. 有多少小于当前数字的数字(C语言)

    给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目。

    Kindear
  • 最大子序列和(leetcode)

    euclid
  • LeetCode268. 缺失数字

    mathor
  • 【Code】关关的刷题日记22——Leetcode 53. Maximum Subarray

    关小刷刷题 22——Leetcode 53. Maximum Subarray 题目 Find the contiguous subarray within a...

    WZEARW
  • LeetCode. 209. 长度最小的子数组

    给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0...

    宇宙之一粟
  • 力扣560——和为K的子数组

    给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。

    健程之道
  • Leetcode#53.Maximum Subarray(最大子序和)

    题目描述 给定一个序列(至少含有 1 个数),从该序列中寻找一个连续的子序列,使得子序列的和最大。 例如,给定序列 [-2,1,-3,4,-1,2,1,-5,4...

    武培轩

扫码关注云+社区

领取腾讯云代金券