組合、排列、子集

題目

  • 46 Permutations

  • 47 Permutations II

  • 31 Next Permutation

  • 784 Letter Case Permutation

  • 78 Subsets

  • 90 Subsets II

  • 2597 The Number of Beautiful Subsets

  • 77 Combinations

  • 39 Combination Sum

  • 40 Combination Sum II

  • 216 Combination Sum III

觀念

組合與排列最大差異,排列是有順序,組合沒有順序,所以排列數通常較大

  • 排列,每個元素都必須包含,所以每次都需要重頭拜訪,需要額外vector used來紀錄該元素是否拜訪過。當然也可迴圈遍歷find()檢查其值是否已包含,但較費時且也較不泛化。

  • 組合沒有順序性可言,不必重頭拜訪,所以可以事先用排序,在借助vector used 或 if(i > s && nums[i] == nums[i-1]) continue; 條件語句。

  • 子集,沒有順序性可言,不必重頭拜訪。紀錄拜訪樹的每個路徑,不拜訪錯過的

  • 陣列有重複元素,可以排序,搭配if(i > s && nums[i] == nums[i-1]) continue;,去掉重複元素,或是vector used,去掉重複元素

  • 78 Subsets

  • 90 Subsets II

  • 784 Letter Case Permutation

DFS

77 Combinations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void traverse(int l, int r, int k, vector<int> &path, vector<vector<int>> &ret){

if(path.size() == k){
ret.push_back(path);
return;
}
for(int i=l;i<=r;++i){
path.push_back(i);
traverse(i+1, r, k, path, ret);
path.pop_back();
}

}
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> ret;
vector<int> path;
traverse(1, n, k, path, ret);
return ret;
}

39 Combination Sum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void traverse(int s, vector<int> &candidates, int target, vector<vector<int>>&ret, vector<int> &path){
// base case
if(target <0) return;
if(target == 0){
ret.push_back(path);
return;
}
for(int i=s;i<candidates.size() ;++i){

path.push_back(candidates[i]);
traverse(i, candidates, target - candidates[i], ret, path);
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> ret;
vector<int> path;
traverse(0, candidates, target, ret, path);
return ret;
}

40 Combination Sum II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
vector<vector<int>> ret;
void traverse(vector<int>& candidates, int target, int l, int r, vector<int>&path){
if(target<0) return;
if(target==0){
ret.push_back(path);
}
for(int i=l;i<=r ;++i){
if (i == l || candidates[i] != candidates[i - 1]){
path.push_back(candidates[i]);
traverse(candidates, target-candidates[i], i+1,r, path);
path.pop_back();
}
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<int> path;
traverse(candidates, target, 0,candidates.size()-1 , path);
return ret;
}

216 Combination Sum III

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
vector<vector<int>> ret;
void traverse(int start, int k, int target, vector<int> &path ){
if(target<0) return;
if(target==0) {
if(path.size() == k) ret.push_back(path);
return;
}

for(int i=start ;i<=9;++i){
// if(cur + i > n) break;
path.push_back(i);
traverse(i+1, k, target-i, path);
path.pop_back();
}
}
vector<vector<int>> combinationSum3(int k, int n) {
vector<int> path;
traverse(1, k, n, path);
return ret;

Permutations

46 Permutations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
vector<vector<int>> ret;
void traverse(vector<int>& nums, vector<int>& path){
if(path.size() == nums.size()){
ret.push_back(path);
return;
}

for(int i=0;i<nums.size(); ++i){
if(find(path.begin(), path.end(), nums[i])!=path.end()) continue;
path.push_back(nums[i]);
traverse(nums, path);
path.pop_back();
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<int> path;
traverse(nums, path);
return ret;
}

47 Permutations II

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
set<vector<int>> ret;
void traverse(vector<int> & nums, vector<int> &path, vector<bool> & visited){

if(path.size() == nums.size()){
// ret.push_back(path);
ret.insert(path);
return;
}
for(int i=0; i<nums.size() ;++i){
if(visited[i]) continue;
visited[i] = true;
path.push_back(nums[i]);
traverse(nums, path, visited);
visited[i] = false;
path.pop_back();
}

}

vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<int> path;
vector<bool> visited(nums.size(), false);
traverse(nums, path, visited);
return vector<vector<int>>(ret.begin(), ret.end());

}

31 Next Permutation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void nextPermutation(vector<int>& nums) {

int n = nums.size();
int k;
for(k = n-2;k>-1 ;k--){
if(nums[k]<nums[k+1]) break;
}

if(k<0){
reverse(nums.begin(), nums.end());
}
else{

int j ;
for(j = n-1;j>k;j--){
if(nums[j]> nums[k]) break;
}

swap(nums[j], nums[k]);
reverse(nums.begin() + k+1, nums.end());
}
}

784 Letter Case Permutation

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
vector<string> ret;
void traverse(string &s, string &path, int l){

if(path.size() == s.size()){
ret.push_back(path);
}
// if(l>= s.size()) reutrn;

for(int i=l;i<s.size();++i){
// 因為只會有大小寫與數字
if(s[i] >='0' && s[i]<='9'){
path.push_back(s[i]);
traverse(s, path, i+1);
path.pop_back();

}
// if(( s[i]>='a' && s[i]<='z') || (s[i]>='A' && s[i]<='Z')){
else{
// 選擇小寫
path.push_back(tolower(s[i]));
traverse(s, path, i+1);
path.pop_back();

// 選擇大寫
path.push_back(toupper(s[i]));
traverse(s, path, i+1);
path.pop_back();
}
}
}
vector<string> letterCasePermutation(string s) {
string path;
traverse(s, path, 0);
return ret;

}

Subsets

78 Subsets

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
vector<vector<int>> ret;
void traverse(vector<int> &nums, vector<int>&path, int l){

ret.push_back(path);
// if(l>=nums.size()) return;

for(int i=l;i<nums.size();++i){
path.push_back(nums[i]);
traverse(nums, path, i+1);
path.pop_back();
}

}
vector<vector<int>> subsets(vector<int>& nums) {

vector<int> path;
traverse(nums, path, 0);
return ret;
}

90 Subsets II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

vector<vector<int>> ret;
void traverse(vector<int> &nums, vector<int>&path, int l){

ret.push_back(path);

for(int i=l;i<nums.size();++i){
if(i>l || nums[i-1]!=nums[i]){
path.push_back(nums[i]);
traverse(nums, path, i+1);
path.pop_back();
}
}

}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<int> path;
traverse(nums, path, 0);
return ret;

}

Combinations

77. Combinations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
vector<vector<int>> ret;
void traverse(int n, int k, vector<int> & path, int start){
// 終止條件
if(path.size() ==k){
ret.push_back(path);
return;
}

for(int i=start;i<=n;++i){
path.push_back(i);
// [2,4] OK , [4,2] not OK -> 只允許遞增,避免重複
traverse(n,k,path, i+1);
path.pop_back();
}
}
vector<vector<int>> combine(int n, int k) {
vector<int> path;
traverse(n,k,path, 1);
return ret;
}
};

39. Combination Sum

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
class Solution {
public:
vector<vector<int>> ret;
void traverse(vector<int>& candidates, int target, vector<int>& path, int s){
// 終止條件
if(target<0) return;
if(target==0){
ret.push_back(path);
return;
}

for(int i=s;i<candidates.size();++i){
// option
if(target < candidates[i]) return;

path.push_back(candidates[i]);
// 因為可重複拿取同一元素
traverse(candidates, target-candidates[i], path, i);
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<int> path;
traverse(candidates, target, path, 0);
return ret;

}
};

40. Combination Sum II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
vector<vector<int>> ret;
void traverse(vector<int>& candidates, int target, vector<int> & path, int j){
if(target<0 ) return;

if(target==0){ret.push_back(path); return;}

for(int i=j;i<candidates.size();++i){
if(i>j && candidates[i-1] == candidates[i]) continue;
path.push_back(candidates[i]);
traverse(candidates, target-candidates[i], path, i+1);
path.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());

vector<int> path;
traverse(candidates, target, path, 0);
return ret;
}
};

216. Combination Sum III

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
vector<vector<int>> ret;
void traverse(int k, int n, int j, vector<int>& path){

if(k == path.size()){
if(n==0) ret.push_back(path);
return;
}
for(int i = j;i<=9;++i){
path.push_back(i);
traverse(k, n-i, i+1, path);
path.pop_back();
}

}
vector<vector<int>> combinationSum3(int k, int n) {

vector<int> path;
traverse(k, n, 1, path);
return ret;
}
};

License