【LeetCode】47.全排列②

版权声明:非商业性使用,禁止演绎,转载请保留原文链接及作者 https://blog.csdn.net/qq_39478237/article/details/89785071

题目描述

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

示例:

输入:

[1,1,2]

输出:

[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]

思路

这道题是上一道题的延伸,由于数组中有可能会出现重复的数字,按照之前的算法会有重复排列产生,因此我们需要判断前面一个数和当前的数是否相等,如果相等,且其对应的visited的值为1,当前数字才能使用,否则需要跳过,这样就不会产生重复排列了。下面方式一就是在排列一的基础上进行剪枝判断。
方式二则使用了set的天然去重功能实现的,总的来说方式二简单一些。

实现代码

方式一

class Solution {
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> ret;
        vector<int> out;
        vector<int> visited(nums.size(),0);
        sort(nums.begin(),nums.end());
        premuteDFS(nums,0,visited,out,ret);
        return ret;
    }
    
    void premuteDFS(vector<int> &num,int level, vector<int> &visited,vector<int> &out,vector<vector<int>>& ret){
        if(level >= num.size()){
            ret.push_back(out);
            return ;
        }
        for(int i= 0;i<num.size();++i){
            if(visited[i] == 1){
                continue;
            }
            if(i>0&& num[i] == num[i-1] && visited[i-1]==0)
                continue;
            visited[i] = 1;
            out.push_back(num[i]);
            premuteDFS(num,level+1,visited,out,ret);
            out.pop_back();
            visited[i] = 0;
               
        }

    }
};

方式二

class Solution {
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        set<vector<int>> res;
        permute(nums,0,res);
        return vector<vector<int>> (res.begin(),res.end());
    }
    
    void permute(vector<int> &nums,int start,set<vector<int>> &res){
        if(start>= nums.size())
            res.insert(nums);
        for(int i=start;i<nums.size();++i){
            if(i != start && nums[i]== nums[start])
                continue;
            swap(nums[i],nums[start]);
            permute(nums,start+1,res);
            swap(nums[i],nums[start]);
        }
    }
};

对于上面的方式二你可能还是疑惑的,我们明明剪枝了为什么还要set的去重?是不是有点重复对于了,其实不然,我们还原用vector数组,并且在主函数调用递归之前给nums排个序,然后测试【1,2,2】,得到结果:

[[1,2,2],[2,1,2],[2,2,1],[2,2,1],2,1,2]]

你会发现结果还是有重复的,那么上面的剪枝到底有啥用?做了啥?
其实,那个剪枝只是为了防止当start=1,i=2时,将两个2交换,这样可以防止(1,2,2)被放入两次。

猜你喜欢

转载自blog.csdn.net/qq_39478237/article/details/89785071