全排列問題

題目:
給定一個(gè) 沒有重復(fù) 數(shù)字的序列,返回其所有可能的全排列。

示例:輸入: [1,2,3]

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

遞歸解法:
如示例中的集合{1,2,3},排列情況有3!=6中排列方法。其第一個(gè)元素有3種選擇1,2,3,對(duì)于第一個(gè)元素為1的排列,其第二個(gè)元素有2種選擇2,3;第一個(gè)元素為2的排列,第二個(gè)元素也有2種選擇1,3;第一個(gè)元素為3的排列,第二個(gè)元素為1,2兩種選擇。

class Solution {

public:

    void swap(vector<int>& nums,int p,int q)
    {
        int tmp=nums[p];
        nums[p]=nums[q];
        nums[q]=tmp;        
    }
    void resove(vector<int> &nums,int n,vector<vector<int>> &result)
    {
        if(n==nums.size())
        {
            result.push_back(nums);
            return;
        }
        for(int i=n;i<nums.size();i++)
        {
            swap(nums,n,i);
            resove(nums,n+1,result);
            swap(nums,n,i);
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> result;
        if(nums.size()<=0) return result;
        resove(nums,0,result);
        return result;
    }
};

字典序解法:
這里先給出算法思想,然后在舉例說明:
a.對(duì)于排列s[1...n],找到所有滿足s[k]<s k+1 的k的最大
值,如果這樣的k不存在,則說明當(dāng)前排列已經(jīng)是a的所有排列
中字典序最大者,所有排列輸出完畢。
b.在s[k+1...n]中,尋找滿足這樣條件的元素l,使得在所有a[l]>a[k]
的元素中,s[l]取得最小值。也就是說s[l]>s[k],但是小于所有其
它大于s[k]的元素。
c.交換s[l]與s[k].
d.對(duì)于s[k+1...n],反轉(zhuǎn)該區(qū)間內(nèi)元素的順序。也就是說s[k+1]與
s[n]交換,s[k+2]與s[n-1]交換,……,這樣就得到了s[1...n]在
字典序中的下一個(gè)排列。
示例:s={1,2,3,4,5}開始排列
假設(shè)此時(shí)序列為:s= {1,3,5,4,2},
經(jīng)過步驟a,找到k=1,s[k+1]=5;
經(jīng)過步驟b,找到l=3,s[l]=4;
步驟c,交換則 s[k(1)]=4,s[l(3)]=3,集合s={1,4,5,3,2};
步驟d,翻轉(zhuǎn)則s={1,4,2,3,5};到此得到下一個(gè)排列。
注意:以上舉例是特殊情況,此示例開始序列為從小到大的排列的最小排列,如果給出的序列不是最小排列的如{0,-1,1},則得不出正確結(jié)果,因題目是無重復(fù)元素,則具體寫代碼時(shí)可以以下標(biāo)作為排列目標(biāo),最后打印時(shí)在確定具體元素。具體代碼如下:
代碼:

class Solution {
public:
    //翻轉(zhuǎn)元素
    void reverse(vector<int> &nums,int s,int e)
    {
        for(int i=s;i<e;i++,e--)
        {
            int tmp=nums[i];
            nums[i]=nums[e];
            nums[e]=tmp;
        }
    }
    //插入元素,用下標(biāo)來找具體元素
    void pushelement(vector<int> &nums,vector<int> &Index,vector<vector<int>> &result)
    {
        vector<int> r;
        for(int i=0;i<Index.size();i++)
        {
            r.push_back(nums[Index[i]]);
        }
        result.push_back(r);
    }
    //無重復(fù)元素,則用下標(biāo)代表集合,以防出現(xiàn)非有序的元素:如[0,-1,1]
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> result;
        if(nums.size()<=0) return result;
        vector<int> Index;
        for(int i=0;i<nums.size();i++)
        {
            Index.push_back(i);
        }
        pushelement(nums,Index,result);
        while(true)
        {
            //尋找最大k值,使得Index[k]<Index[k+1]
            int k=Index.size()-1;
            bool bexist=false;
            for(;k>0;k--)
            {
                if(Index[k]>Index[k-1])
                {
                    k-=1;
                    bexist=true;
                    break;
                }
            }
            if(bexist==false)
            {
                return result;
            }
            //尋找最小值l,使得Index[l]>Index[k];
            int l=k+1;
            int tmp=Index[k+1];
            for(int i=k+2;i<Index.size();i++)
            {
                if(Index[i]>Index[k] && Index[i]<tmp)
                {
                    l=i;
                    tmp=Index[l];
                }
            }
            //交換Index[k]與Index[l];
            tmp=Index[k];
            Index[k]=Index[l];
            Index[l]=tmp;
            //翻轉(zhuǎn)元素
            reverse(Index,k+1,Index.size()-1);
            pushelement(nums,Index,result);
        }
        return result;
    }
};

題目: 給定一個(gè)可包含重復(fù)數(shù)字的序列,返回所有不重復(fù)的全排列。
示例:輸入: [1,1,2]
輸出:[ [1,1,2],[1,2,1], [2,1,1]]
思路和上述,無重復(fù)的排列相同,只是在最開始對(duì)數(shù)組進(jìn)行了排序,得到最小排列,另外為了去重: if(Index[i]>Index[k] && Index[i]<tmp) 此處改為 : if(Index[i]>Index[k] && Index[i]<=tmp),就能保證得到非重復(fù)的元素,其實(shí),無重復(fù)的排列也可添加上等號(hào)不影響結(jié)果,本例這樣寫只是為了示例。代碼如下:

class Solution {
public:
    //翻轉(zhuǎn)元素
    void reverse(vector<int> &nums,int s,int e)
    {
        for(int i=s;i<e;i++,e--)
        {
            int tmp=nums[i];
            nums[i]=nums[e];
            nums[e]=tmp;
        }
    }
    //無重復(fù)元素,則用下標(biāo)代表集合,以防出現(xiàn)非有序的元素:如[0,-1,1]
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<vector<int>> result;
        if(nums.size()<=0) return result;
        //排序,得到最小排列
        sort(nums.begin(),nums.end());
        result.push_back(nums);
        while(true)
        {
            //尋找最大k值,使得nums[k]<nums[k+1]
            int k=nums.size()-1;
            bool bexist=false;
            for(;k>0;k--)
            {
                if(nums[k]>nums[k-1])
                {
                    k-=1;
                    bexist=true;
                    break;
                }
            }
            if(bexist==false)
            {
                return result;
            }
            //尋找最小值l,使得nums[l]>numa[k];
            int l=k+1;
            int tmp=nums[k+1];
            for(int i=k+2;i<nums.size();i++)
            {
                //此處去重,可與無重復(fù)數(shù)字的全排列作比較,觀察條件設(shè)置
                if(nums[i]>nums[k] && nums[i]<=tmp)
                {
                    l=i;
                    tmp=nums[l];
                }
            }
            //交換nums[k]與nums[l];
            tmp=nums[k];
            nums[k]=nums[l];
            nums[l]=tmp;
            //翻轉(zhuǎn)元素
            reverse(nums,k+1,nums.size()-1);
            result.push_back(nums);
        }
        return result;
    }
};
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容