N选K组合(无重复版) 给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。
N选K组合解题思路 状态:第i个
选择: n-i个选择
路径:path选择
结果集:列表
结束条件: 找到所有的组合; path路径到了k
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 vector <int > path;void  dfs (int  u, int  start_idx)   {    if  (u == k) {                  return ;     }          for  (int  i = start_idx; i <= n; ++i) {         path.push_back(i);         dfs(u + 1 , i + 1 ) ;          path.pop_back();     }          for  (int  i = start_idx; i <= n - (k - path.size()); ++i) {         path.push_back(i);         dfs(u + 1 , i + 1 );         path.pop_back();     } } dfs(0 , 0 ); 
 
和为n的K个数的组合 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
N选K组合的和解题思路 状态:第i个
选择: 9-i个选择
路径:path选择
结果集:列表
结束条件: 找到所有的组合; path路径到了k,sum ok
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 vector <int > path;void  dfs (int  u, int  sum, int  start)   {    if  (sum > n) {return ;}     if  (u == k) {         if  (sum == 0 ) {             res.push_back(path);         }         return ;     }     for  (int  i = start; i <= 9  - (k - path.size()) + 1 ; i++) {         path.push_back(i);         dfs(u + 1 , sum - i, i + 1 );         path.pop_back();     } } dfs(0 , n, 0 ); 
 
和为N的组合(无限选取版) 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
candidates找和为target解题思路 状态:第i个
选择: 每次都有N个选择
路径:path选择
结果集:列表
结束条件: 找到所有的组合; path路径到了k,sum ok
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 void  dfs (vector <int >& d, int  u, int  sum, int  start)   {    if  (sum > target) {return ;}     if  (sum == target) {         res.push_back(path);         return ;     }     for  (int  i = start; i < n; ++i) {         path.push_back(d[i]);         dfs(d, u + 1 , sum + d[i], i);          path.pop_back();     } } void  dfs (vector <int >& d, int  u, int  sum, int  start)   {    if  (sum > target) {return ;}     if  (sum == target) {         res.push_back(path);         return ;     }          for  (int  i = start; i < n && sum+d[i] <= target; ++i) {         path.push_back(d[i]);         dfs(d, u + 1 , sum + d[i], i);          path.pop_back();     } } 
 
和为N的组合(有重复,仅用一次) 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。
说明: 所有数字(包括目标数)都是正整数。解集不能包含重复的组合。
//需要进行排序预处理,从大到小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void  dfs (vector <int >& d, int  u, int  sum, int  start_index)   {        if  (sum > target) {return ;}         if  (sum == target) {             res.push_back(path);             return ;         }         for  (int  i = start_index; i < n && sum + d[i] <= target; ++i) {                          if  (i >= 1  && d[i] == d[i - 1 ] && used[i - 1 ] == false ) {continue ;}             path.push_back(d[i]);             used[i] = true ;             dfs(d, u + 1 , sum + d[i], i + 1 );             used[i] = false ;             path.pop_back();         }     } 
 
所有数字的排列(无重复版) 给定一个 没有重复  数字的序列,返回其所有可能的全排列。
解法1 给坑u找元素i 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void  dfs (vector <int >& d, int  u)   {    if  (u == n) {         res.push_back(path);         return ;     }     for  (int  i = 0 ; i < n; ++i ) {         if  (used[i]) continue ;         path.push_back(d[i]);                  used[i] = true ;         dfs(d, u + 1 );         used[i] =false ;         path.pop_back();     } } 
 
解法2: 特定元素(u)选择坑位(i) //后面可以选择的坑原来越少了; u是第一个元素;
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 class  Solution  {public :    vector <vector <int >> res;     vector <int > path;          void  dfs (vector <int >& nums, int  u, int  state)   {         if  (u == int (nums.size())) {             res.push_back(path);             return ;         }                  for  (int  i = 0 ; i < nums.size(); ++i) {             if  (!(state >> i & 1 )) {                                  path[i]= nums[u];                 dfs(nums, u + 1 , state + (1  << i));             }         }     }          vector <vector <int >> permutation (vector <int >& nums)   {         path.resize(nums.size());         sort(nums.begin(), nums.end());         dfs(nums, 0 , 0 , 0 );         return  res;     } }; 注意到前面的state与path的配合使用,有两个目的:保存当前坑位存了哪些元素了,保存坑位的使用情况。 有没有什么手段呢? path可以d来替代;d的前半部分作为坑使用,后半部分保持原功能; 但是坑占用之前,需要保存其原值,一举两得。所以就有了下面这种解法。          void  dfs (vector <int >& d, int  u)   {         if  (u == n) {             res.push_back(d);             return ;         }                  for  (int  i = u; i < n; ++i ) {             swap(d[u], d[i]);                dfs(d, u + 1 );               swap(d[u], d[i]);         }     } 
 
所有数字的排列(数字重复) 输入一组数字(可能包含重复数字),输出其所有的排列方式。
样例 输入:[1,2,3]
输出:       [         [1,2,3],         [1,3,2],         [2,1,3],         [2,3,1],         [3,1,2],         [3,2,1]       ]
为坑(u)选择合适的元素(i) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void  dfs (int  u)   {    if  (u == nums.size()) {         res.push_back(path);         return ;     }     for  (int  i = 0 ; i < nums.size(); i++) {         if  (i > 0  &&  nums[i] == nums[i - 1 ] && !used[i - 1 ]) continue ;          if  (used[i]) continue ;         used[i] = true ;                  path.push_back(nums[i]);         dfs(u + 1 );         path.pop_back();         used[i] = false ;     } } 
 
特定元素(u)选择坑位(i) 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 class  Solution  {public :    vector <vector <int >> res;     vector <int > path;          void  dfs (vector <int >& nums, int  u, int  start, int  state)   {         if  (u == int (nums.size())) {             res.push_back(path);             return ;         }                           if  (!u || nums[u] != nums[u - 1 ]) start = 0 ;                          for  (int  i = start; i < nums.size(); ++i) {             if  (!(state >> i & 1 )) {                                  path[i]= nums[u];                 dfs(nums, u + 1 , i + 1 , state + (1  << i));             }         }     }          vector <vector <int >> permutation (vector <int >& nums)   {         path.resize(nums.size());         sort(nums.begin(), nums.end());         dfs(nums, 0 , 0 , 0 );         return  res;     } }; 
 
所有递增子序列 给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。
示例:
输入: [4, 6, 7, 7] 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
说明:
给定数组的长度不会超过15。 数组中的整数范围是 [-100,100]。 给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况。
解题思路 
因为找到是递增子序列,所以不能排序;也就不能通过排序来去重了 
可以考虑用hash_map来做去重。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void  dfs (int  u, int  start)   {       if  (u >= 2 ) {            res.push_back(path);                    }        unordered_set <int > iset;        for  (int  i = start; i < d.size(); i++) {            if  (iset.count(d[i])) continue ;            if  (path.size() && path.back() > d[i]) continue ;            iset.insert(d[i]);            path.push_back(d[i]);            dfs(u + 1 , i + 1 );            path.pop_back();        }    } 
 
https://zhuanlan.zhihu.com/p/339849416