字符串的全排列

問題

輸入一個字符串,按字典序打印出該字符串中字符的所有排列。例如輸入字符串a(chǎn)bc,則打印出由字符a,b,c所能排列出來的所有字符串a(chǎn)bc,acb,bac,bca,cab和cba。

地址:https://www.nowcoder.com/practice/fe6b651b66ae47d7acce78ffdd9a96c7?tpId=13&tqId=11180&tPage=2&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

遞歸

思路:從字符串中選出一個字符作為排列的第一個字符,然后對剩余的字符進(jìn)行全排列。如此遞歸處理,從而得到所有字符的全排列。

分析:我們可以先根據(jù)一個實際的例子想想,怎樣才能無遺漏的輸出全排列:

兩個數(shù)就不用說了,對于 ab,只有 ab 和 ba 兩種
三個數(shù),比如 abc,我們先分為三種情況,就是 a 開頭,b 開頭和 c 開頭
對于 a 開頭的情況,剩下 b 和 c,這就回到了兩個數(shù)的排列;
對于 b 開頭的情況,剩下 a 和 c,這也回到了兩個數(shù)的排列;
c 開頭的情況同理;
四個數(shù),先按照開頭分為四種情況,然后按照三個數(shù)的排列去處理
……
以此類推

由此可看出,這是一個遞歸。就好像求斐波那契數(shù)列的某一個元素,我們要先求出前面的;要想求出前面的,我們就要求出更前面的。記 “斐波那契數(shù)列的第 n 位” 這件事為 F(n),則有 F(n) = F(n - 1) + F(n - 2)。

類似地,記 “求出 n 個字符串的全排列” 這件事為 P(n),則有P(n) = 分別以這n個字符之一開頭 + P(n - 1)。其中,P(n - 1) 表示去掉那個開頭字符的剩余字符串的全排列。哪怕只有兩個字符,比如對于上面例子中的 ab,同樣符合這一條結(jié)論。

  • 分析:以 'abc' 為例,執(zhí)行步驟如下:
  1. a 作為開頭 -> 求 bc 全排列 -> 得到 bc 和 cb -> 與 a 合并 -> 得到 abc 和 acb
  2. b 作為開頭 -> 求 ac 全排列 -> 得到 ac 和 ca -> 與 b 合并 -> 得到 bac 和 bca
  3. c 作為開頭 -> 求 ab 全排列 -> 得到 ab 和 ba -> 與 c 合并 -> 得到 cab 和 cba

注:之前遞歸過程選擇的字符,下一次不能再被選。

時間復(fù)雜度:O(n!)。

function permutation(str) {
    if(str.length == 0) {
        return [];
    }
    var result = [];
    var sortTemp = '';
    var arr = str.split('');
    // var len = arr.length;
    var result = sortString(arr, sortTemp, result);
    return result;

    function sortString(arr, sortTemp, res) {
        if(arr.length == 0) {
            return res.push(sortTemp);
        } else {
            let isRepeat = {};
            for(let i = 0; i < arr.length; i++) { // 不要用 len
                if(!isRepeat[arr[i]]) {
                    let temp = arr.splice(i, 1)[0]; // i 取出第i個字符作為第一個字符
                    sortTemp += temp;
                    sortString(arr, sortTemp, res); // 固定第一個字符的剩下字符的全排列已完成
                    arr.splice(i, 0, temp); // i 補全 恢復(fù)原字符串
                    sortTemp = sortTemp.slice(0, sortTemp.length - 1); // 清空sortTemp: 每次截掉字符串中的最后一個字符
                    isRepeat[temp] = true; // 相同的字符便不再在第一個字符中固定并對剩下的字符進(jìn)行全排列了
                }
            }    
        }
        return res;
    }
}
permutation('abc')

這里固定字符串?dāng)?shù)組元素中的第一個字符的方式:是利用數(shù)組中splice()方法通過截取出來(刪掉一個元素),完成全排列后再將該字符補全回原字符串中splice()(添加元素)的方式。遍歷該字符串?dāng)?shù)組,依次截取掉每個字符元素的方式來作為字符串?dāng)?shù)組元素的第一個字符。

當(dāng)然還可以通過依次向后交換的方式、或者取出元素以后向后插入的方式、以及經(jīng)典的回溯法的方式等等。

References

leetcode題解(遞歸和回溯法)
July 算法習(xí)題 - 字符串4(全排列和全組合)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 字符串的全排列 題目描述: 輸入一個字符串,打印出該字符串中字符的所有排列。 例如輸入字符串a(chǎn)bc,則輸出由字符a...
    MinoyJet閱讀 11,460評論 4 11
  • 1. 排列 鏈接注意字符重復(fù)與非重復(fù)兩種情況的區(qū)別。非遞歸實現(xiàn)有點麻煩 2. 組合 2.1 什么是組合 有abc得...
    yangqi916閱讀 964評論 0 1
  • 字符串全排列是劍指offer上的一道題,由于早期碰到就不是很理解,今天特地整理一下思路 1.遞歸: 1)對于不存在...
    NickStudy閱讀 360評論 0 0
  • 1. width 和 height 設(shè)置的不對的時候,會出現(xiàn)邊框線如圖所示: 解決辦法:Echarts/index...
    超人阿亮閱讀 1,984評論 0 1
  • 風(fēng)孩子 爸爸一級生氣時,他鼻子如同火車冒煙的洞,噴出煙來;二級生氣時,罵人的話就像太上老君的三昧真火一樣從他的嘴里...
    Fenny_官閱讀 423評論 0 0

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