JavaScript实现全排列算法

题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

基本思路

采用插空的方法:每次选一个字符,在剩余字符串中进行插空。

例如:有字符串”abc”,取出a,剩余”bc”,剩余部分可以形成三个间隔( )b( )c( )或 ( )c( )b( ) 一共两种方案, 然后将a插入到3个空中,所以总共有6种方案。

JavaScript实现

完整代码如下:

function Permutation(str){
    if(str.length == 0){
        return [];
    }
    var result = [];
    if(str.length == 1){
        return [str];
    }else{//把str分为两部分,第一部分为第一个字母str[0],第二部分为剩余的字符串str.slice(1),把Permutation(str.slice(1))作为一个已知量。
        var rest = Permutation(str.slice(1));//递归,Permutation(str.slice(1))表示剩余部分字符串的全排列。
        for (var j = 0; j < rest.length; j++) {//插空
             for (var k = 0; k < rest[j].length+1; k++) {
                 var temp = rest[j].slice(0,k)+str[0]+rest[j].slice(k);
                 result.push(temp);
             }
        }
        //去掉result中重复的元素
        var res = [];
        for(var k = 0;k<result.length;k++){
            if(res.indexOf(result[k]) === -1){
                res.push(result[k]);
            }
        }
        return res.sort();
    }
}

代码分析

确定用递归的方法来解决问题是关键的一点。类似于数学归纳法:
1. 证明当n=1时命题成立。
2. 假设n=m时命题成立,那么可以推导出在n=m+1时命题也成立。

假设我们已经知道了n-1的输出,要由这个输出得出n的输出。在这个问题里,n-1的输出,对应着长度比当前输入的字符串少1的字符串。也就是说,假如我们已经知道了“abc”的全排列输出的集合,现在再给你一个“d”,要怎样得出新的全排列呢?
很简单,只要对于集合中每一个元素,把d插入到任意相邻字母之间(或者头部和尾部),就可以得到一个新的排列。例如对于元素“acb”,插入到第一个位置,即可得到“dacb”,插入其余位置,可得到“adcb”,“acdb”,“acbd”。容易证明这样形成的新元素不会有重复。

我们把原字符串分成两部分,第一部分为字符串的第一个字符即str[0],第二部分为剩余的字符串即str.slice(1)。那么我们只要知道剩余字符串的全排列,然后将第一个字符插入剩余字符串全排列的间隔即可。根据以上的假设,现在可以把 Permutation(str.slice(1)) 作为一个已知量看待。注意:代码中的rest[j].length+1这里必须加上1,因为slice()方法的截取范围是“左闭右开”区间。
通过上面的方法,可以得到所有排列组合的情况。然而,对于"aab"得到的结果是["aab","aab","aba","aba","baa","baa"],所以还需要一个去重操作。

参考文档

全排列算法的JS实现 - 迷路的约翰

猜你喜欢

转载自blog.csdn.net/xuedan1992/article/details/80171647