全排列 II

原题:

给定一个可包含重复数字的序列 nums按任意顺序 返回所有不重复的全排列。

示例 1:

  1. 输入:nums = [1,1,2]
  2. 输出:
  3. [[1,1,2],
  4. [1,2,1],
  5. [2,1,1]]

示例 2:

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

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10

解题方法:

解法一:

class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<bool> used(nums.size(),false);
        backtracking(nums,used);

        return res;
    }

    void backtracking(vector<int>& nums,vector<bool>& used)
    {
        if(path.size()==nums.size())
        {
            res.push_back(path);
            return;
        }
        for(int i=0;i<nums.size();i++)
        {
            if(used[i]) continue;
            if(i>0&&nums[i]==nums[i-1]&&used[i-1]) continue;
            used[i]=true;
            path.push_back(nums[i]);
            backtracking(nums,used);
            used[i]=false;
            path.pop_back();
        }
        return;
    }
};

解法二:

class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<bool> used(nums.size(),false);
        backtracking(nums,used);

        return res;
    }

    void backtracking(vector<int>& nums,vector<bool>& used)
    {
        if(path.size()==nums.size())
        {
            res.push_back(path);
            return;
        }
        for(int i=0;i<nums.size();i++)
        {
            if(used[i]) continue;
            if(i>0&&nums[i]==nums[i-1]&&!used[i-1]) continue;
            used[i]=true;
            path.push_back(nums[i]);
            backtracking(nums,used);
            used[i]=false;
            path.pop_back();
        }
        return;
    }
};

做题小结:

解针对法一:

主要还是在去重上面需要下功夫:

1.首先需要注意同层不能重复使用,因此需要

if(used[i]) continue;

2.而要做到结果中不含重复数组,则必须要保证在同层遍历中,已经使用过的“数值”只使用一次,因此需要

if(i>0&&nums[i]==nums[i-1]&&used[i-1]) continue;

这里需要注意used[i-1]很必要,否则不能保证至少有一个数值被使用

针对解法二:

  1. 在去重时需要深刻理解used为true和为false时分别代表什么

    1. used[i - 1] == true,说明同一树支nums[i - 1]使用过 ; used[i - 1] == false,说明同一树层nums[i - 1]使用过 ; 如果同一树层nums[i - 1]使用过则直接跳过。因此可以看到解法二跟解法一的区别就在于used[i-1]要求变成了false,但结果却一样
    2. 对于排列问题,树层上去重和树枝上去重,都是可以的,但是树层上去重效率更高!
    3. 要理解used为false时同层被遍历,要明白i是从0开始依次遍历的。