字符串的全排列

問題

輸入一個字符串,按字典序打印出該字符串中字符的全部排列。例如輸入字符串abc,則打印出由字符a,b,c所能排列出來的全部字符串abc,acb,bac,bca,cab和cba。算法

地址:https://www.nowcoder.com/prac...segmentfault

遞歸

思路:從字符串中選出一個字符做爲排列的第一個字符,而後對剩餘的字符進行全排列。如此遞歸處理,從而獲得全部字符的全排列。數組

分析:咱們能夠先根據一個實際的例子想一想,怎樣才能無遺漏的輸出全排列:post

兩個數就不用說了,對於 ab,只有 ab 和 ba 兩種
三個數,好比 abc,咱們先分爲三種狀況,就是 a 開頭,b 開頭和 c 開頭
對於 a 開頭的狀況,剩下 b 和 c,這就回到了兩個數的排列;
對於 b 開頭的狀況,剩下 a 和 c,這也回到了兩個數的排列;
c 開頭的狀況同理;
四個數,先按照開頭分爲四種狀況,而後按照三個數的排列去處理
……
以此類推

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

相似地,記 「求出 n 個字符串的全排列」 這件事爲 P(n),則有 P(n) = 分別以這n個字符之一開頭 + P(n - 1)。其中,P(n - 1) 表示去掉那個開頭字符的剩餘字符串的全排列。哪怕只有兩個字符,好比對於上面例子中的 ab,一樣符合這一條結論。遞歸

  • 分析:以 'abc' 爲例,執行步驟以下:
  1. a 做爲開頭 -> 求 bc 全排列 -> 獲得 bc 和 cb -> 與 a 合併 -> 獲得 abc 和 acb
  2. b 做爲開頭 -> 求 ac 全排列 -> 獲得 ac 和 ca -> 與 b 合併 -> 獲得 bac 和 bca
  3. c 做爲開頭 -> 求 ab 全排列 -> 獲得 ab 和 ba -> 與 c 合併 -> 獲得 cab 和 cba

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

時間複雜度: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 補全 恢復原字符串
                    sortTemp = sortTemp.slice(0, sortTemp.length - 1); // 清空sortTemp: 每次截掉字符串中的最後一個字符
                    isRepeat[temp] = true; // 相同的字符便再也不在第一個字符中固定並對剩下的字符進行全排列了
                }
            }    
        }
        return res;
    }
}
permutation('abc')

這裏固定字符串數組元素中的第一個字符的方式:是利用數組中splice()方法經過截取出來(刪掉一個元素),完成全排列後再將該字符補全回原字符串中splice()(添加元素)的方式。遍歷該字符串數組,依次截取掉每一個字符元素的方式來做爲字符串數組元素的第一個字符。get

固然還能夠經過依次向後交換的方式、或者取出元素之後向後插入的方式、以及經典的回溯法的方式等等。it

References

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

相關文章
相關標籤/搜索