三種解法解含重複數字的全排列

LeetCode 47 全排列II

給定一個可包含重複數字的序列,返回所有不重複的全排列。

示例:

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

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/permutations-ii

解法一

每次讓一個數字做爲首數字,剩下的遞歸排列。通過swap來改變首數字。
依次將待排列的集合規模變小,若某一個數字做過首字符則跳過。

如 1 2 2 3
先讓1做第一個數字, 剩下子序列2 2 3進行遞歸
對2 2 3進行排列
可得 1 2 2 3、1 2 3 2 、1 3 2 2
當st=1,i=2時 nums[st]=2,nums[st]=2 此時進入isSwap函數判斷,st=1,end=i=2,再nums[st]~nums[end-1]中出現了nums[end]的數字,說明nums[end]已經在st、st+1…,end-1位置中出現過,無需重複排列,所以continue。

class Solution {
public:
    void swap(int &a,int &b){
        int tmp=a;
        a=b;
        b=tmp;
    }
    bool isSwap(vector<int>& nums,int st,int end){
        for(int i=st;i<end;i++){
            if(nums[i]==nums[end]){
                return false;
            }
        }
        return true;
    }
    void  curusion(int st,vector<int>& nums,int numsSize,vector<vector<int>>& res,vector<int> & tmp){
        if(st==numsSize){
            for(int i=0;i<numsSize;i++){
                tmp.push_back(nums[i]);
            }
            res.push_back(tmp);
            tmp.clear();
            return;
        }
        for(int i=st;i<numsSize;i++){
            if(!isSwap(nums,st,i))
                continue;
            swap(nums[i],nums[st]);
            curusion(st+1,nums,numsSize,res,tmp);
            swap(nums[i],nums[st]);
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> res;
        vector<int> tmp;
        curusion(0,nums,nums.size(),res,tmp);
        return res;
    }
    
};

提交結果:
在這裏插入圖片描述

解法二 用map映射

一開始想用一個數組去標記某個數是否已經在某個位置上出現過,但由於可能出現負數問題,只能利用map進行標記。

class Solution {
public:
    void swap(int &a,int &b){
        int tmp=a;
        a=b;
        b=tmp;
    }
   
    void  curusion(int st,vector<int>& nums,int numsSize,vector<vector<int>>& res,vector<int> & tmp){
        if(st==numsSize){
            for(int i=0;i<numsSize;i++){
                tmp.push_back(nums[i]);
            }
            res.push_back(tmp);
            tmp.clear();
            return;
        }
        map<int,int>mp;
        for(auto e:nums){
            mp[e]=0;
        }  
        for(int i=st;i<numsSize;i++){
            if(mp[nums[i]]==1)
                continue;
            mp[nums[i]]=1;
            swap(nums[i],nums[st]);
            curusion(st+1,nums,numsSize,res,tmp);
            swap(nums[i],nums[st]);
        }//一整個for循環是nums[st]~nums[numsSize-1]的序列中進行排列,對一個子序列排列使用一個map映射,並且每一個子序列開始排序前要清零
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> res;
        vector<int> tmp;
        curusion(0,nums,nums.size(),res,tmp);
        return res;
    }
    
};

提交結果如下:
在這裏插入圖片描述

解法三

在leetcode題解中學到用從map中選數字排列,每次從map中選未使用過的非重複數字或者未全部使用完的重複數字。
如 1 2 3 3
初始時 map映射爲 [1,1],[2,1],[3,2]
第一個數字從1,2,3中選1 ,遞歸排列後三個數字,map映射爲 [1,0],[2,1],[3,2]
第二個數字從1,2,3中選2,遞歸排列後兩個數字,map映射爲[1,0],[2,0],[3,2]
第三個數字從1,2,3中選3,遞歸排列後一個數字,map映射爲[1,0],[2,0],[3,1]
第四個數字從1,2,3中選3,map映射爲[1,0],[2,0],[3,0],得到一個排列1 2 2 3加入結果集合依次返回上一層,依次恢復mp[3]=1,mp[3]=2,mp[2]=1,返回到第二個數字
第二個數字從1,2,3中選3(遍歷2後是3)遞歸排列第三個數字,map映射爲[1,0],[2,1],[3,1]
第三個數字從1,2,3中選2,遞歸排列第四個數字,map映射爲[1,0],[2,0],[3,1]
第四個數字從1,2,3中選3,得到1 3 2 3加入結果集,恢復mp[3]=1,mp[2]=1,返回到排列第三個數字
第三個數字從1,2,3中選3,第四個數字選2 得到1 3 3 2
同理依次得到 2 1 3 3,2 3 1 3,3 1 2 3, 3 2 1 3 ,3 2 3 1,3 3 1 2,3 3 2 1

class Solution {
public:
    void  curusion(int k,vector<int>& nums,int numsSize,vector<vector<int>>& res,vector<int> & tmp,map<int,int> &mp){

        if(k==numsSize){
            res.push_back(tmp);
            return;
        }
        for(auto &p: mp){
            if(p.second==0) 
                continue;
            p.second--;
            tmp.push_back(p.first);
            curusion(k+1,nums,numsSize,res,tmp,mp);
            tmp.pop_back();
            p.second++;
        }

    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> res;
        vector<int> tmp;
        map<int,int> mp;
        for(int e:nums){
            mp[e]++;
        }
        curusion(0,nums,nums.size(),res,tmp,mp);
        return res;
    }
};  

提交結果如下在這裏插入圖片描述

發佈了38 篇原創文章 · 獲贊 13 · 訪問量 4028
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章