46&&47.Permutations I&&II && 40 .Combination Sum II(回溯)
Permutations I
Given a collection of distinct numbers, return all possible permutations.
For example,
[1,2,3]
have the following permutations:
[1,2,3]
, [1,3,2]
, [2,1,3]
, [2,3,1]
, [3,1,2]
, and [3,2,1]
.
class Solution { private: vector<vector<int>> res; public: void getPer(vector<int>&nums,int index,int lenth) { if(index==lenth) res.push_back(nums); int temp; for(int i=index;i<lenth;i++) { temp=nums[i]; nums[i]=nums[index]; nums[index]=temp; getPer(nums,index+1,lenth); temp= nums[i]; nums[i]=nums[index]; nums[index]=temp; } return ; } vector<vector<int>> permute(vector<int>& nums) { getPer(nums,0,nums.size()); return res; } };
Permutations II
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
For example,
[1,1,2]
have the following unique permutations:
[1,1,2]
, [1,2,1]
, and [2,1,1]
.
这道题其实也纠结了我很久。没想到只需要定义一个set来存储已经交换过的元素值就可以把问题完美的解决了。
class Solution { public: vector<vector<int> > permuteUnique(vector<int> &num) { if(num.size() <= 0) return res; permCore(num, 0); return res; } private: vector<vector<int> > res; void permCore(vector<int> &num, int st){ if(st == num.size()) res.push_back(num); else{ set<int> swp; for(int i = st; i < num.size(); ++i){ if(swp.find(num[i]) != swp.end()) continue; swp.insert(num[i]); swap(num, st, i); permCore(num, st+1); swap(num, st, i); } } } void swap(vector<int> &num, int left, int right){ int tmp = num[left]; num[left] = num[right]; num[right] = tmp; } };
II:
Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
Each number in C may only be used once in the combination.
Note:
- All numbers (including target) will be positive integers.
- Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
- The solution set must not contain duplicate combinations.
For example, given candidate set 10,1,2,7,6,1,5
and target 8
,
A solution set is: [1, 7]
[1, 2, 5]
[2, 6]
[1, 1, 6]
class Solution { private: vector<vector<int>> res; vector<int> temp; public: void combinationSum(vector<int>& candidates, int target,vector<int>::iterator initer,int tempsum) { if(tempsum==target) { if(find(res.begin(),res.end(),temp)==res.end()) res.push_back(temp); return ; } if(initer==candidates.end()||tempsum>target) return ; for(vector<int>::iterator iter=initer;iter!=candidates.end();iter++) { temp.push_back(*iter); combinationSum(candidates,target,iter+1, tempsum+*iter); temp.pop_back(); } } vector<vector<int>> combinationSum2(vector<int>& candidates, int target) { sort(candidates.begin(),candidates.end()); vector<int>::iterator initer=candidates.begin(); combinationSum(candidates,target,initer,0); return res; } };
方法二
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
class Solution { public : vector< int > singleRes; vector<vector< int >> res; void judgeSubSum(vector< int >& candidates, int target, int index) { if (target < 0) { return ; } if (target == 0) { res.push_back(singleRes); return ; } int len= candidates.size(); for ( int i = index; i <len; i++) { if (i>index&& candidates[i] == candidates[i-1]) { continue ; } int val = candidates[i]; singleRes.push_back(val); judgeSubSum(candidates, target - val,i+1); singleRes.pop_back(); } return ; } vector<vector< int >> combinationSum2(vector< int >& candidates, int target) { int len= candidates.size(); sort(candidates.begin(), candidates.end()); for ( int i = 0; i <len; i++) { if (i>0&& candidates[i] == candidates[i-1]) { continue ; } int val = candidates[i]; singleRes.push_back(val); judgeSubSum(candidates, target - val,i+1); singleRes.pop_back(); } return res; } }; |
解释语句: if cur > begin and candidates[cur-1] == candidates[cur] 是如何避免重复的。
这个避免重复当思想是在是太重要了。
这个方法最重要的作用是,可以让同一层级,不出现相同的元素。即
1
/ \
2 2 这种情况不会发生 但是却允许了不同层级之间的重复即:
/ \
5 5
例2
1
/
2 这种情况确是允许的
/
2
为何会有这种神奇的效果呢?
首先 cur-1 == cur 是用于判定当前元素是否和之前元素相同的语句。这个语句就能砍掉例1。
可是问题来了,如果把所有当前与之前一个元素相同的都砍掉,那么例二的情况也会消失。
因为当第二个2出现的时候,他就和前一个2相同了。
那么如何保留例2呢?
那么就用cur > begin 来避免这种情况,你发现例1中的两个2是处在同一个层级上的,
例2的两个2是处在不同层级上的。
在一个for循环中,所有被遍历到的数都是属于一个层级的。我们要让一个层级中,
必须出现且只出现一个2,那么就放过第一个出现重复的2,但不放过后面出现的2。
第一个出现的2的特点就是 cur == begin. 第二个出现的2 特点是cur > begin.