全排列算法-遞歸&字典序?qū)崿F(xiàn)(C++)

全排列:

從n個(gè)不同元素中任取m(m≤n)個(gè)元素庸追,按照一定的順序排列起來,叫做從n個(gè)不同元素中取出m個(gè)元素的一個(gè)排列涝缝。當(dāng)m=n時(shí)所有的排列情況叫全排列扑庞。
例如:

1、2拒逮、3三個(gè)元素的全排列為:
{1罐氨,2,3}滩援,{1栅隐,3,2}玩徊,{2租悄,1,3}恩袱,{2泣棋,3,1}畔塔,{3潭辈,1,2}澈吨,{3萎胰,2,1}棚辽。

解法1(遞歸)

如下圖:要對(duì)1技竟、2、3屈藐、4進(jìn)行排序榔组,第一個(gè)位置上的元素有四種可能:1或2或3或4,假如已經(jīng)確定了第一個(gè)元素為4联逻,剩下的第二個(gè)位置上可以是1搓扯、2、3包归,很顯然這具有遞歸結(jié)構(gòu)锨推,如果原始要排列的數(shù)組順序?yàn)?、2、3换可、4椎椰,現(xiàn)在只要分別交換1、2沾鳄,1慨飘、3,1译荞、4然后對(duì)剩下的3個(gè)元素進(jìn)行遞歸的排列瓤的。

image

代碼:

    void permute(string str, int k) {
        if (k == str.size() - 1) {
            cout << str << endl;
        } else if (k < str.size() - 1) {
            for (int i = k; i < str.size(); i++) {
                swap(str[i], str[k]);
                permute(str, k + 1);
                swap(str[i], str[k]);
            }
        }
    }

    void permute(string str) {
        if (!str.empty()) {
            permute(str, 0);
        }
    }

遞歸方法會(huì)對(duì)重復(fù)元素進(jìn)行交換比如使用遞歸對(duì){1,1}進(jìn)行全排序會(huì)輸出:{1吞歼,1}圈膏,{1,1}兩個(gè)重復(fù)的結(jié)果篙骡。要在排序的時(shí)候去掉重復(fù)結(jié)果稽坤,可以修改一下代碼如下:

    void permute(string str, int k) {
        if (k == str.size() - 1) {
            cout << str << endl;
        } else if (k < str.size() - 1) {
            for (int i = k; i < str.size(); i++) {
                if (i == k || str[i] != str[k]) {
                    swap(str[i], str[k]);
                    permute(str, k + 1);
                    swap(str[i], str[k]);
                }
            }
        }
    }

    void permute(string str) {
        if (!str.empty()) {
            permute(str, 0);
        }
    }
解法2(字典序法)

字典序法
對(duì)給定的字符集中的字符規(guī)定了一個(gè)先后關(guān)系,在此基礎(chǔ)上規(guī)定兩個(gè)全排列的先后是從左到右逐個(gè)比較對(duì)應(yīng)的字符的先后医增。
列如:對(duì)a、b老虫、c進(jìn)行排序的結(jié)果是{a,b,c}叶骨、{a,c,b}、{b,a,c}祈匙、{b,c,a}忽刽、{c,a,b}、{c,b,a}
字典序法的優(yōu)點(diǎn)是排列的結(jié)果按照順序輸出并且對(duì)于重復(fù)的元素不進(jìn)行重復(fù)排序夺欲。

字典排序法的思想:

例如:對(duì)元素1跪帝,2,3些阅,4進(jìn)行排序伞剑,假設(shè)默認(rèn)的數(shù)組順序?yàn)閧1,2市埋,3黎泣,4},先輸出第一個(gè)排列:1缤谎、2抒倚、3、4坷澡。然后從右向左找到第一個(gè)非遞增的數(shù)托呕,4,3,因?yàn)?比4小项郊,交換3馅扣、4,并且對(duì)3后面的數(shù)進(jìn)行逆序排列呆抑,第二個(gè)排列為{1岂嗓,2,4鹊碍,3}厌殉,再從右向左3,4侈咕,2公罕,發(fā)現(xiàn)2比4小,交換從右向左第一個(gè)比2大的數(shù)耀销,交換后{1楼眷,3,4熊尉,2}再對(duì)3后面的數(shù)進(jìn)行逆序排列第三個(gè)序列為:{1罐柳,3,2狰住,4}
依次循環(huán)直到數(shù)組成為完全遞減數(shù)組結(jié)束1张吉、2、3催植、4字典排序的最大序列為{4肮蛹,3,2创南,1}伦忠。

代碼:

    void permute(string str) {
        if (!str.empty()) {
            permute(str, 0);
        }
    }

    string permute(string &src, int k) {
        sort(src.begin(), src.end());
        int len = src.length();
        bool end = false;
        while (true) {
            cout << src << endl;

            int index = 0;
            int j;

            // 從右到左找到第一個(gè)非遞增的元素
            for (j = len - 2; j >= 0; j--) {
                if (src[j] < src[j + 1]) {
                    index = j;
                    break;
                } else if (j == 0) {
                    end = true;
                    break;
                }
            }

            // 遍歷已經(jīng)結(jié)束
            if (end) {
                break;
            }

            // 從右向左找到第一個(gè)比非遞增元素大的元素
            for (j = len - 1; j >= 0; j--) {
                if (src[j] > src[index]) {
                    break;
                }
            }

            swap(src[index], src[j]);
            reverse(src, index + 1);
        }
    }

    void reverse(string &str, int index) {
        int i = index;
        int j = str.length() - 1;
        while (i < j) {
            swap(str[i], str[j]);
            i++;
            j--;
        }
    }

轉(zhuǎn)載請(qǐng)注明出處::https://juejin.cn/post/6897762695689273351
參考文獻(xiàn):筆試面試算法經(jīng)典--全排列算法-遞歸&字典序?qū)崿F(xiàn)(Java)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市稿辙,隨后出現(xiàn)的幾起案子昆码,更是在濱河造成了極大的恐慌,老刑警劉巖邻储,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件未桥,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡芥备,警方通過查閱死者的電腦和手機(jī)冬耿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萌壳,“玉大人亦镶,你說我怎么就攤上這事日月。” “怎么了缤骨?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵爱咬,是天一觀的道長。 經(jīng)常有香客問我绊起,道長精拟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任虱歪,我火速辦了婚禮蜂绎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘笋鄙。我一直安慰自己师枣,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布萧落。 她就那樣靜靜地躺著践美,像睡著了一般。 火紅的嫁衣襯著肌膚如雪找岖。 梳的紋絲不亂的頭發(fā)上陨倡,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音许布,去河邊找鬼兴革。 笑死,一個(gè)胖子當(dāng)著我的面吹牛爹脾,可吹牛的內(nèi)容都是我干的帖旨。 我是一名探鬼主播箕昭,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼灵妨,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了落竹?” 一聲冷哼從身側(cè)響起泌霍,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎述召,沒想到半個(gè)月后朱转,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡积暖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年藤为,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夺刑。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缅疟,死狀恐怖分别,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情存淫,我是刑警寧澤耘斩,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站桅咆,受9級(jí)特大地震影響括授,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜岩饼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一荚虚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧忌愚,春花似錦曲管、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至简十,卻和暖如春檬某,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背螟蝙。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工恢恼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胰默。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓场斑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親牵署。 傳聞我的和親對(duì)象是個(gè)殘疾皇子漏隐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容