Combination Sum 系列问题(leetcode dfs回溯,动归)由浅入深DFS
2016-09-28 09:14
417 查看
Combination Sum问题 在leetcode的有一系列题目
采用dfs 回溯的方法求解,当然代码仍需优化,剪枝是个重点
需要仔细弄懂最初的第一题,后面的就是各种调整了
39 Combination Sum(https://leetcode.com/problems/combination-sum/)
The same repeated number may be chosen from C unlimited number of times.
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
For example, given candidate set [2, 3, 6, 7] and target 7,
A solution set is:
此题的搜索树如下
https://leetcode.com/problems/combination-sum-ii/
在dfs之前,数据是排好序的,但是会有连续相同数字出现的情况,计算是会有重复的???
注意一个问题: 下面的两个if在代码中的顺序不要颠倒, why?
去重条件就一个if, why
最终的ac代码:
https://leetcode.com/problems/combination-sum-iii/
有了上面两题的求解思路和基础,这题基本上就是个自我变化的过程。不过若一开始就给出这题,应该也能想到类似的方法
ac代码
For example,
If n = 4 and k = 2, a solution is:
ac代码如下
Example:
Follow up:
What if negative numbers are allowed in the given array?
How does it change the problem?
What limitation we need to add to the question to allow negative numbers?
应采用动态规划的方法
采用dfs 回溯的方法求解,当然代码仍需优化,剪枝是个重点
需要仔细弄懂最初的第一题,后面的就是各种调整了
39 Combination Sum(https://leetcode.com/problems/combination-sum/)
39. Combination Sum
Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.The same repeated number may be chosen from C unlimited number of times.
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
For example, given candidate set [2, 3, 6, 7] and target 7,
A solution set is:
[ [7], [2, 2, 3] ]
此题的搜索树如下
第一次, 按照普通的dfs,debug发现有重复的结果
class Solution { private: vector<vector<int>> ans; vector<int> rs; public: void dfs(int nowSum, vector<int> cand, int candSize, int target) { if (nowSum > target) return; if (nowSum == target) { ans.push_back(rs); return; } for (int i = 0; i < candSize; i++){ rs.push_back(cand[i]); dfs(nowSum + cand[i], cand, candSize,target); rs.pop_back(); } } vector<vector<int>> combinationSum(vector<int>& candidates, int target) { int len = candidates.size(); if (len == 0) return ans; sort(candidates.begin(), candidates.end());// 排序 dfs(0, candidates,len, target); return ans; } };
第二次,去除重复结果
//加一个nowIndex,每次只从当前到数组末尾,不选择比当前小的值,避免重复 class Solution { private: vector<vector<int>> ans; vector<int> rs; public: void dfs(int nowIndex,int nowSum, vector<int> cand, int candSize, int target) { if (nowSum > target) return; if (nowSum == target) { ans.push_back(rs); return; } for (int i = nowIndex; i < candSize; i++){ rs.push_back(cand[i]); dfs(i,nowSum + cand[i], cand, candSize,target); rs.pop_back(); } } vector<vector<int>> combinationSum(vector<int>& candidates, int target) { int len = candidates.size(); if (len == 0) return ans; sort(candidates.begin(), candidates.end());// 排序 dfs(0,0, candidates,len, target); return ans; } };
ac,上面在计算结果 太耗时,因为有大量的没必要的计算
此题最终的ac代码class Solution { private: vector<vector<int>> ans; vector<int> rs; public: void dfs(int nowIndex,int nowSum, vector<int> cand, int candSize, int target) { if (nowSum > target) return; if (nowSum == target) { ans.push_back(rs); return; } for (int i = nowIndex; i < candSize; i++){ if (nowSum + cand[i] <= target) // 因为cand是排序好的,显然会有大量的重复,应该避免,相当于剪枝 { rs.push_back(cand[i]); dfs(i, nowSum + cand[i], cand, candSize, target); rs.pop_back();// 回溯 } else continue; } } vector<vector<int>> combinationSum(vector<int>& candidates, int target) { int len = candidates.size(); if (len == 0) return ans; sort(candidates.begin(), candidates.end());// 排序 dfs(0,0, candidates,len, target); return ans; } };
40. Combination Sum II
题目地址https://leetcode.com/problems/combination-sum-ii/
有重复结果的代码1
class Solution { public: vector<int> candi; int candiLen; int tar; vector<vector<int>> rs; vector<int> ans; void dfs(int curIndex, int curSum) { if(curSum == tar) { for(int i=0;i<(int)ans.size();i++) cout << ans[i] << " "; cout << endl; rs.push_back(ans); return; } if(curIndex >= candiLen || curSum > tar) return; for(int i = curIndex; i < candiLen; i++) { if(candi[i] > tar || candi[i] + curSum > tar) break; ans.push_back(candi[i]); dfs(i + 1, curSum + candi[i]); ans.pop_back(); } } vector<vector<int>> combinationSum2(vector<int>& candidates, int target) { candi = candidates; candiLen = candi.size(); if(candiLen > 1) sort(candi.begin(), candi.end()); tar = target; ans.clear(); rs.clear(); dfs(0,0); return rs; } };
在dfs之前,数据是排好序的,但是会有连续相同数字出现的情况,计算是会有重复的???
上面的去重条件加上 就可以ac了
class Solution { public: vector<int> candi; int candiLen; int tar; vector<vector<int>> rs; vector<int> ans; void dfs(int curIndex, int curSum) { if(curSum == tar) { for(int i=0;i<(int)ans.size();i++) cout << ans[i] << " "; cout << endl; rs.push_back(ans); return; } if(curIndex >= candiLen || curSum > tar) return; for(int i = curIndex; i < candiLen; i++) { if(candi[i] > tar || candi[i] + curSum > tar) break; if(i > curIndex && candi[i] == candi[i-1]) // 去重 continue; ans.push_back(candi[i]); dfs(i + 1, curSum + candi[i]); ans.pop_back(); } } vector<vector<int>> combinationSum2(vector<int>& candidates, int target) { candi = candidates; candiLen = candi.size(); if(candiLen > 1) sort(candi.begin(), candi.end()); tar = target; ans.clear(); rs.clear(); dfs(0,0); return rs; } };
注意一个问题: 下面的两个if在代码中的顺序不要颠倒, why?
if(curSum == tar) { for(int i=0;i<(int)ans.size();i++) cout << ans[i] << " "; cout << endl; rs.push_back(ans); return; } if(curIndex >= candiLen || curSum > tar) return;
去重条件就一个if, why
ac2
在上一题的基础上,保证数组中的每个数字不能够重复计算,所以需要设计去重的功能,在dfs时做了修改,发现仍然重复,所以有用到了c++stl map结构去重最终的ac代码:
class Solution { private: map<vector<int>, int> mp; vector<vector<int>> ans; vector<int> rs; public: void dfs(int nowIndex,int nowSum, vector<int> cand, int candSize, int target) { if (nowSum > target) return; if (nowSum == target) { // 因为仍然会有重复,利用map/set去重 if (mp[rs] == 0) { ans.push_back(rs); mp[rs] = 1; } return; } // 从当前的下一个开始,不包括自己,因为每个数组中的数字 for (int i = nowIndex + 1; i < candSize; i++){ if (nowSum + cand[i] <= target) // 因为cand是排序好的,显然会有大量的重复,应该避免,相当于剪枝 { rs.push_back(cand[i]); dfs(i, nowSum + cand[i], cand, candSize, target); rs.pop_back();// 回溯 } else continue; } } vector<vector<int>> combinationSum2(vector<int>& candidates, int target) { int len = candidates.size(); if (len == 0) return ans; sort(candidates.begin(), candidates.end());// 排序 dfs(-1,0, candidates,len, target); return ans; } };
216. Combination Sum III
题目地址https://leetcode.com/problems/combination-sum-iii/
有了上面两题的求解思路和基础,这题基本上就是个自我变化的过程。不过若一开始就给出这题,应该也能想到类似的方法
ac代码
class Solution { private: vector<vector<int>> ans; vector<int> rs; public: void dfs(int nowIndex,int nowSum, vector<int> cand, int candSize, int target,int nowRsSize,int k) { if (nowSum > target || nowRsSize > k) return; if (nowSum < target && nowRsSize == k) return; if (nowSum == target && nowRsSize == k) { ans.push_back(rs); return; } // 从当前的下一个开始,不包括自己,因为每个数组中的数字 for (int i = nowIndex + 1; i < candSize; i++){ if (nowSum + cand[i] <= target && nowRsSize <= k) // 因为cand是排序好的,显然会有大量的重复,应该避免,相当于剪枝 { rs.push_back(cand[i]); dfs(i, nowSum + cand[i], cand, candSize, target,nowRsSize+1,k); rs.pop_back();// 回溯 } else continue; } } vector<vector<int>> combinationSum3(int k, int n) { vector<int> candidates{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; dfs(-1,0, candidates,9, n,0,k); return ans; } };
77. Combinations
题目地址
https://leetcode.com/submissions/detail/78260609/题目描述
Given two integers n and k, return all possible combinations of k numbers out of 1 … n.For example,
If n = 4 and k = 2, a solution is:
[ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
求解
采用递归方式求解,因为数字不会重复,长度也限定了,思路同前面几题ac代码如下
class Solution { private: vector< vector<int> >ans; vector<int> v; public: void dfs(int n, int k, int nowK, int indexN) { if (nowK > k) return; if (nowK == k) { /*for (int i = 0; i < k; i++) cout << v[i] << " "; cout << endl;*/ ans.push_back(v); return; } for (int i = indexN; i <= n; i++) { v.push_back(i); dfs(n, k, nowK + 1, i + 1); v.pop_back(); } } vector<vector<int>> combine(int n, int k) { dfs(n, k, 0, 1); return ans; } };
377. Combination Sum IV
题目地址
https://leetcode.com/problems/combination-sum-iv/题目描述
Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.Example:
nums = [1, 2, 3] target = 4 The possible combination ways are: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1) Note that different sequences are counted as different combinations. Therefore the output is 7.
Follow up:
What if negative numbers are allowed in the given array?
How does it change the problem?
What limitation we need to add to the question to allow negative numbers?
求解
采用dfs会超时,此题结果是很大的,因为数字可以重复,任意组合应采用动态规划的方法
class Solution { public: int combinationSum4(vector<int>& nums, int target) { int len = nums.size(); sort(nums.begin(), nums.end()); vector<int> dp(target + 1, 0); // dp[i] 表示 能组成 等于i的个数 dp[i - num] + num 可以凑成 dp[i] dp[0] = 1; for (int i = 1; i <= target; i++) { for (int j = 0; j < len; j++) { if (nums[j] <= i) dp[i] += dp[i - nums[j]]; else break; } } return dp[target]; } };
#
相关文章推荐
- LeetCode-39-Combination Sum, 回溯dfs,Python的list.append()覆盖前面,tuple,set
- [leetcode] 回溯法 Combination Sum 系列问题
- 从Leetcode的Combination Sum系列谈起回溯法
- [LeetCode系列]子集枚举问题[无重复元素]
- 分配糖果问题——Leetcode系列(十五)
- HDU/HDOJ 2563 统计问题 回溯发DFS
- LeetCode 笔记系列 14 N-Queen II [思考的深度问题]
- 八皇后问题 DFS,回溯剪枝 //http://poj.grids.cn/practice/2698
- [LeetCode系列]链表环探测问题II
- poj 1321 棋盘问题(dfs,回溯)
- 子集系列(一) 传统subset 问题,例 [LeetCode] Subset, Subset II, Bloomberg 的一道面试题
- [LeetCode系列]括号生成问题
- POJ 1321 棋盘问题(DFS+回溯)
- hdu 2553 N皇后问题(DFS+回溯)
- [LeetCode系列]最大容器问题
- [LeetCode系列] 二叉树最大深度求解问题(C++递归解法)
- leetcode: 2Sum/3Sum/3SumClosest/4Sum系列问题
- 棋盘问题 DFS+回溯
- [leetcode刷题系列]Combination Sum
- [LeetCode系列]N皇后问题递归解法 -- 位操作方式