全排列问题

题目:
给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:输入: [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中排列方法。其第一个元素有3种选择1,2,3,对于第一个元素为1的排列,其第二个元素有2种选择2,3;第一个元素为2的排列,第二个元素也有2种选择1,3;第一个元素为3的排列,第二个元素为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.对于排列s[1...n],找到所有满足s[k]<s k+1 的k的最大
值,如果这样的k不存在,则说明当前排列已经是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.对于s[k+1...n],反转该区间内元素的顺序。也就是说s[k+1]与
s[n]交换,s[k+2]与s[n-1]交换,……,这样就得到了s[1...n]在
字典序中的下一个排列。
示例:s={1,2,3,4,5}开始排列
假设此时序列为:s= {1,3,5,4,2},
经过步骤a,找到k=1,s[k+1]=5;
经过步骤b,找到l=3,s[l]=4;
步骤c,交换则 s[k(1)]=4,s[l(3)]=3,集合s={1,4,5,3,2};
步骤d,翻转则s={1,4,2,3,5};到此得到下一个排列。
注意:以上举例是特殊情况,此示例开始序列为从小到大的排列的最小排列,如果给出的序列不是最小排列的如{0,-1,1},则得不出正确结果,因题目是无重复元素,则具体写代码时可以以下标作为排列目标,最后打印时在确定具体元素。具体代码如下:
代码:

class Solution {
public:
    //翻转元素
    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;
        }
    }
    //插入元素,用下标来找具体元素
    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);
    }
    //无重复元素,则用下标代表集合,以防出现非有序的元素:如[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;
            //翻转元素
            reverse(Index,k+1,Index.size()-1);
            pushelement(nums,Index,result);
        }
        return result;
    }
};

题目: 给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:输入: [1,1,2]
输出:[ [1,1,2],[1,2,1], [2,1,1]]
思路和上述,无重复的排列相同,只是在最开始对数组进行了排序,得到最小排列,另外为了去重: if(Index[i]>Index[k] && Index[i]<tmp) 此处改为 : if(Index[i]>Index[k] && Index[i]<=tmp),就能保证得到非重复的元素,其实,无重复的排列也可添加上等号不影响结果,本例这样写只是为了示例。代码如下:

class Solution {
public:
    //翻转元素
    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;
        }
    }
    //无重复元素,则用下标代表集合,以防出现非有序的元素:如[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++)
            {
                //此处去重,可与无重复数字的全排列作比较,观察条件设置
                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;
            //翻转元素
            reverse(nums,k+1,nums.size()-1);
            result.push_back(nums);
        }
        return result;
    }
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342