Leetcode之combinations、Permutations(两种)、Combination Sum(两种)、Subset(两种)、permutation-sequence

combinations【子集+回溯法】

题目描述: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],
]

回溯法的思想:尝试+回溯+remove

class Solution {
public:
    /*在1-n里面找到k个数的组合*/
    vector<vector<int> > combine(int n, int k) {
        vector<int> list;//存放一种组合
        vector<vector<int> > results; //存放所以组合
        backtracking(1,n,k,list,results);
        return results;
    }
     //回溯算法-尝试+回溯+remove
    /*从start到end里面寻找k个数字*/
    void backtracking(int start,int end,int k,vector<int> &list,vector<vector<int> > &results){
        if(k==0){ 
            results.push_back(list);
            return;
        }else{
            for(int i=start;i<=end;i++){
                list.push_back(i); //尝试
                backtracking(i+1,end,k-1,list,results); //回溯
                list.pop_back();
            }
        }
    }
};

Permutations【全排列-不排序-回溯法-vector】

题目描述:Given a collection of 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 {
public:
    //回溯法
    //找出Nums里的元素的所有排列组合(nums是collection:可能存在重复元素)
    /*重要:交换-回溯-交换*/
    vector<vector<int> > permute(vector<int> &num) {
        vector<vector<int> > results;
        backtracking(0,num,results);
        return results;
    }
    //*l:记录当前取得是当前下标为l的元素
    void backtracking(int l,vector<int> &num,vector<vector<int> > &results){
        if(l==num.size()-1){
            results.push_back(num);
            return;
        }else{
            for(int i=l;i<=num.size()-1;i++){
                swap(num[i],num[l]);
                backtracking(l+1,num,results);
                swap(num[l],num[i]);
            }
        }
    }
};

Permutations-II【全排列-不排序-回溯法-set】

题目描述: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].

思路:同 上面的pertatins相比,用set替换vector,由于set.insert的特征;注意外层为set,内层vector不可以用vectorname.size()

class Solution {
public:
    //回溯法
    //Based on permutation:用set而不是采用vector!!
    vector<vector<int> > permuteUnique(vector<int> &num) {
        int n=num.size();
        set<vector<int> > res;
        backtracking(0,n,num,res);
        vector<vector<int> > results;
        results.assign(res.begin(),res.end());
        return results;
    }
    //*l:记录当前取得是当前下标为l的元素
    void backtracking(int l,int n,vector<int> &num,set<vector<int> > &res){
        if(l==n){
            res.insert(num);
            return;
        }else{
            for(int i=l;i<n;i++){
                swap(num[i],num[l]);
                backtracking(l+1,n,num,res);
                swap(num[l],num[i]);
            }
        }
    }
};

Combination Sum【子集-排序-回溯法-vector】

题目描述: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.
Elements in a combination (a 1, a 2, … , a k) must be in non-descending order. (ie, a 1 ≤ a 2 ≤ … ≤ a k).The solution set must not contain duplicate combinations.
For example, given candidate set2,3,6,7and target7,
A solution set is:
[7]
[2, 2, 3]

回溯算法:尝试+回溯+remove;注意利用candidates均为正数控制循环次数 c a n d i d a t e s [ i ] &lt; = t a r g e candidates[i]&lt;=targe candidates[i]<=targe),利用start控制重复组合!

相比于permutation:有target,故先对数组排序

class Solution {
public:
    vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
        //先将candidates排序
        sort(candidates.begin(),candidates.end());
        vector<int> list;//记录一种组合
        vector<vector<int> > results;//记录返回结果
        backtracking(candidates,0,target,list,results);
        return results;
    }
    
    /*回溯算法--尝试+回溯+remove控制*/
    void backtracking(vector<int> &candidates,int start,int target,vector<int> &list,vector<vector<int> > &results){
        if(target==0){
            results.push_back(list);
            return;
        }else{
            /*错误:for(int i=0;i<candidates.size();i++)*/
            /*注意:利用start控制重复*/
            /*利用candidates均为正数优化!!candidates[i]<=target!!*/
            for(int i=start;i<candidates.size()&& candidates[i]<=target;i++){
                list.push_back(candidates[i]); //尝试
                backtracking(candidates,i,target-candidates[i],list,results);
                list.pop_back();
            }
        }
    }
};

Combination Sum-II【子集-排序-回溯法-set】

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 (a 1, a 2, … , a k) must be in non-descending order. (ie, a 1 ≤ a 2 ≤ … ≤ a k).The solution set must not contain duplicate combinations.For example, given candidate set10,1,2,7,6,1,5and target8,
A solution set is:
[1, 7]
[1, 2, 5]
[2, 6]
[1, 1, 6]

**回溯算法:尝试+回溯+remove;
同上题的相似点:

  • 注意利用candidates均为正数控制循环次数( c a n d i d a t e s [ i ] &lt; = t a r g e candidates[i]&lt;=targe candidates[i]<=targe),利用start控制重复组合;

不同于上题:

  • (1)clollection包括list和set,set是不允许重复的,但由于list是可以重复,所以collection可能重复。所以上题的candidates排完序本身就没有重复元素**
  • (2)此题为了避免结果重复,引入set记录结果,因为插入一个已经存在的元素对容器没有影响

相比于permutation:有target,故先对数组排序

class Solution {
public:
    vector<vector<int> > combinationSum2(vector<int> &num, int target) {
        //先将num排序
        sort(num.begin(),num.end());
        vector<int> list;//记录一种组合
        //利用set记录结果,保证没有重复
        set<vector<int> > setOfResults;//记录返回结果
        vector<vector<int> > results;
        backtracking(num,0,target,list,setOfResults);
        //vector赋值assign:将set中的元素赋值给vector
        results.assign(setOfResults.begin(),setOfResults.end());
        return results;
    }
    
    /*回溯算法--尝试+回溯+remove控制*/
    void backtracking(vector<int> &candidates,int start,int target,vector<int> &list,set<vector<int> > &results){
        if(target==0){
            //set包含不重复的关键字,因此插入一个已经存在的元素对容器没有影响
            results.insert(list);
            return;
        }else{
            /*错误:for(int i=0;i<candidates.size();i++)*/
            /*注意:利用start控制重复*/
            /*利用candidates均为正数优化!!candidates[i]<=target!!*/
            for(int i=start;i<candidates.size()&& candidates[i]<=target;i++){
                list.push_back(candidates[i]); //尝试
                backtracking(candidates,i+1,target-candidates[i],list,results);
                list.pop_back();
            }
        }
    }
};

Subset【子集-排序-回溯法-vector】

题目描述:Given a set of distinct integers, S, return all possible subsets.Note:Elements in a subset must be in non-descending order.The solution set must not contain duplicate subsets.
For example,
If S =[1,2,3], a solution is:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]

思路:for循环实现递归+getList函数实现回溯
解释:
(1)排序的原因是为了保持子集里的元素非减
(2)回溯法:尝试+回溯+remove
(3)vector:尽管结果要求不含重复元素,但因为S中本身是不含重复元素的,故直接用vector即可

class Solution {
public:
    //注意:用vector指针访问元素时,也可以用size()求长度
    vector<vector<int> > subsets(vector<int> &S) {
        sort(S.begin(),S.end());//对s排序:为了nondescending
        vector<int> list;
        vector<vector<int> > results;//记录返回结果
        for(int i=0;i<=S.size();i++)
            getList(0,i,S,list,results);
        //step1:在num中取i个元素即可
        return results;
    }
    
    //在有序s中取n个元素,list是n个元素的集合,allList是所有list的集合
    void getList(int start,int n,vector<int> s,vector<int> &list,vector<vector<int> > &results){
        if(n==0){
            results.push_back(list);
            return;
        }else{
            for(int i=start;i<s.size();i++){
                list.push_back(s[i]);//尝试
                getList(i+1,n-1,s,list,results);
                list.pop_back();
            }
        }
    }
};

Subset-II【子集-排序-回溯法-set】

题目描述:Given a collection of integers that might contain duplicates, S, return all possible subsets.Note:Elements in a subset must be in non-descending order.
The solution set must not contain duplicate subsets.For example,
If S =[1,2,2], a solution is:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]

思路:for循环实现递归+getList函数实现回溯
解释:
(1)排序的原因是为了保持子集里的元素非减
(2)回溯法:尝试+回溯+remove
(3)set:结果要求不含重复元素,而且S中本身是可能含重复元素,故用set

class Solution {
public:
    //注意:使用set
    vector<vector<int> > subsetsWithDup(vector<int> &S) {
        sort(S.begin(),S.end());//对s排序:为了nondescending
        vector<int> list;
        set<vector<int> > results;//记录返回结果
        vector<vector<int> > res;
        for(int i=0;i<=S.size();i++)
            getList(0,i,S,list,results);
        res.assign(results.begin(),results.end());
        //step1:在num中取i个元素即可
        return res;
    }
    
    //在有序s中取n个元素,list是n个元素的集合,allList是所有list的集合
    void getList(int start,int n,vector<int> s,vector<int> &list,set<vector<int> > &results){
        if(n==0){
            results.insert(list);
            return;
        }else{
            for(int i=start;i<s.size();i++){
                list.push_back(s[i]);//尝试
                getList(i+1,n-1,s,list,results);
                list.pop_back();
            }
        }
    }
};

permutation-sequence【非回溯】

题目描述:The set[1,2,3,…,n]contains a total of n! unique permutations【排列组合】.By listing and labeling all of the permutations in order,We get the following sequence (ie, for n = 3):
“123”
“132”
“213”
“231”
“312”
“321”
Given n and k, return the k th permutation sequence.Note: Given n will be between 1 and 9 inclusive.

class Solution {
public:
    string getPermutation(int n, int k) {
        string res;
        string num = "123456789";
        vector<int> f(n, 1);
        for (int i = 1; i < n; ++i) f[i] = f[i - 1] * i;
        --k;
        for (int i = n; i >= 1; --i) {
            int j = k / f[i - 1];
            k %= f[i - 1];
            res.push_back(num[j]);
            num.erase(j, 1);  //不能用vector.erase(begin+index)因为begin会改变
        }
        return res;
    }
};

推荐资料

手把手教你中的回溯算法——多一点套路
leetcode回溯法欣赏——配合前文套路教学效果更佳

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值