全排列-决策树&剪枝&回溯&递归

题目

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例

输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

算法描述

解决一个回溯问题,实际上就是一个决策树的遍历过程。一般来说,我们需要解决三个问题:
路径:也就是已经做出的选择。
选择列表:也就是你当前可以做的选择。
结束条件:也就是到达决策树底层,无法再做选择的条件。

我们所使用的框架基本就是:

LinkedList result = new LinkedList();
public void backtrack(路径,选择列表){
    if(满足结束条件){
        result.add(结果);
    }
    for(选择:选择列表){
        做出选择;
        backtrack(路径,选择列表);
        撤销选择;
    }
}

其中最关键的点就是:在递归之前做选择,在递归之后撤销选择。

方法一

class Solution {
private:
    vector<vector<int>>ans;
    int n;
public:
    vector<vector<int>> permute(vector<int>& nums) {
        n=nums.size();
        permutation(0,nums);
        return ans;
    }
    void permutation(int start,vector<int>& nums){
        if(start==n-1)
        {
            ans.push_back(nums);
            return ;
        }
        for(int i=start;i<n;i++){
            swap(nums[i],nums[start]);
            permutation(start+1,nums);
            swap(nums[i],nums[start]);
        }
    }
};

方法二

class Solution {
private:
    vector<vector<int>>ans;
    vector<int> curr;
    int used[10000];
    int n;
public:
    vector<vector<int>> permute(vector<int>& nums) {
        n=nums.size();
        for(int i=0;i<n;i++)
            used[i]=0;
        sort(nums.begin(),nums.end());
        permutation(nums);
        return ans;
    }
    void permutation(vector<int>& nums){
        if(curr.size()==nums.size()){
            ans.push_back(curr);
            return;
        }
        for(int i=0;i<n;i++){
            if(used[i]){
                continue;
            }
            
                curr.push_back(nums[i]);
                used[i]=1;
                permutation(nums);
                curr.pop_back();
                used[i]=0;
        }
    }
};

举一反三

题目描述

给定一个可包含重复数字的序列,返回所有不重复的全排列。

示例

输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]

算法描述

由于本题需要返回所有不重复的全排列,有限制条件,所以需要进行剪枝。这里第一步先要给数组进行排序。
首先,先要给nums进行排序,这样的做目的是方便剪枝
其次,我们已经选择过的不需要再放进去了
接下来,如果当前节点与他的前一个节点一样,并其他的前一个节点已经被遍历过了,那我们也就不需要了。

代码

class Solution {
private:
    vector<vector<int>>ans;
    vector<int> curr;
    int used[10000];
    int n;
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        n=nums.size();
        for(int i=0;i<n;i++)
            used[i]=0;
        sort(nums.begin(),nums.end());
        permutation(nums);
        return ans;
    }
    void permutation(vector<int>& nums){
        if(curr.size()==nums.size()){
            ans.push_back(curr);
            return;
        }
        for(int i=0;i<n;i++){
            if(used[i]){
                continue;
            }
            if(i>0&&nums[i]==nums[i-1]&&used[i-1])
                continue;
                curr.push_back(nums[i]);
                used[i]=1;
                permutation(nums);
                curr.pop_back();
                used[i]=0;
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值