47. 全排列 II

47. 全排列 II_第1张图片
有重复元素的回溯算法,比全排列I难,重点有2个,第一个是去重,第二个是不要加入重复元素。
排列都是要从0到n的,比组合复杂一点,组合的话就不是i>=1然后和前一位比就能简单去重了
1:去重,先对其进行排序,主要是为了在同一层不要选择相同的数字,然后和前面一位一样的话就continue。
2:不要加入重复元素:用一个map记录所有数字的出现次数,每次dfs这个数字,就将这个数字–,记得dfs后加回来,如果ma[当前数字]==0就continue。

class Solution {
public:
    //用set可以解决大部分去重问题,但是空复不行
    void dfs(vector<int>& nums){
        if(tmp.size() == nums.size()){
            res.push_back(tmp);
            return;
        }
        for(int i = 0; i < nums.size(); ++i){
            //排序过后,在同一层如果当前字符和前一个字符一样,直接continue
            //如果112这种,如果在选第一个数字的时候我们选了第一个1作为第一个1,然后求出所有以第一个1为第一个1的结果,回到这层循环,继续选择第一个数字,此时我们选择第二个1作为第一个1是浪费时间,后面所有操作都是取的重复数组
            if(ma[nums[i]] == 0 || (i >= 1 && nums[i] == nums[i-1])) continue;
            tmp.push_back(nums[i]);
            ma[nums[i]]--;
            dfs(nums);
            tmp.pop_back();
            ma[nums[i]]++;
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        //用重复数字的全排列,不能用find来判断是否要这个数字了
        //可以用一个map来记录每个数字的出现次数,如果出现次数超了,就不要加入这个数字了
        //重点不能重复
        sort(nums.begin(),nums.end());
        for(int x : nums){
            ma[x]++;
        }
        dfs(nums);
        return res;
    }
private:
    vector<vector<int>> res;
    vector<int> tmp;
    unordered_map<int,int> ma;
};

你可能感兴趣的:(#,回溯算法,leetcode,leetcode,算法)