码迷,mamicode.com
首页 > 其他好文 > 详细

LeetCode494. 目标和

时间:2021-02-18 13:00:43      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:oid   数据量   backtrack   turn   nbsp   ndt   i++   path   tracking   

题目

分析

这道题开始我是想用回溯,但一看数据量,肯定会超时(指数级的时间复杂度)。没有思路,想着应该是dp,怎么进行转化,转为我们熟悉的问题呢?题目的意思就是说将数组分成两堆n1,n2,使得 n1 - n2 = S 。且有n1 + n2 = sum。由这两个式子可得 n1 + n2 = 2 * n2 + S = sum。=》 n2 = (sum - S) / 2。这样我们可看出了也就是找到一个子集合,使得集合之和等于(sum - S) / 2的方法有多少种?这里我们可能还是会想回溯暴搜比如LeetCode 39组合之和,这里也可用dp来做。由于每个数只能用一次,这就转换为01背包问题。直接用二维dp熟悉了,直接用一维dp来做。dp[j] 表示容量为j 有多少种方案。怎么推导动态转移方程呢?还是仿照01背包问题的思想。就是用集合的思想,先去再加。

 dp[j] += dp[j-nums[i]]——这也是求组合问题常用的转移方程。

注意:初始化时,dp【0】要为1,若为0,则dp数组全为0。这里1可以理解为容量0啥也不装,为1种方案。

代码

 1 class Solution {
 2 public:
 3     int findTargetSumWays(vector<int>& nums, int S) {
 4         int sum = 0;
 5         for(auto s:nums){
 6             sum += s;
 7         }
 8         if(sum < S) return 0; //边界
 9         int t = (sum - S);
10         if(t%2) return 0;  //奇数没有方案
11         vector<int>dp(t/2+1,0);
12         dp[0] = 1;//初始化为1,容量为0时装0件物品,一种方案,若为0,则全部为0
13         for(int i = 0;i < nums.size();i++){
14             for(int j = t / 2;j >= nums[i];j--){
15                 dp[j] += dp[j-nums[i]];
16             }
17         }
18         return dp[t/2];
19     }
20 };

时间复杂度O(n*m),n为背包个数,m为背包容量。

空间复杂度O(m)

回溯法代码

 1 class Solution {
 2     vector<vector<int>>res;
 3     vector<int>path;
 4     void backtracking(vector<int>nums,int target,int sum,int startIndex){
 5         if(sum == target){
 6             res.push_back(path);
 7         }
 8         for(int i = startIndex;i < nums.size() && nums[i] + sum <= target;i++){
 9             //做剪枝,如果nums[i] + sum > target直接终止
10             path.push_back(nums[i]);
11             sum += nums[i];
12             backtracking(nums,target,sum,i+1);
13             sum -= nums[i];
14             path.pop_back();
15         }
16     }
17 
18 public:
19     int findTargetSumWays(vector<int>& nums, int S) {
20         int sum = 0;
21         for(auto s:nums){
22             sum += s;
23         }
24         if(sum < S) return 0;
25         int t = (sum - S);
26         if(t%2) return 0;  //奇数没有方案
27         //用回溯来代替dp
28         sort(nums.begin(),nums.end()); //回溯中存在剪枝要先排序
29         backtracking(nums,t/2,0,0);
30         return res.size();
31     }
32 };

LeetCode494. 目标和

标签:oid   数据量   backtrack   turn   nbsp   ndt   i++   path   tracking   

原文地址:https://www.cnblogs.com/fresh-coder/p/14404190.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!