剑指offer[27]——字符串的排列

题目描述

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

输入描述:

输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

这道题目我们换一种思路,假设题目中给的字符串全部是不重复字母,然后题目要求我们给出字符串排列的种数,这个时候大家心里应该能够想到使用排列组合的方法来解决这道题目。

首先,我们把四个字母的位置当做是四个杯子,假设四个字母是ABCD,第一个杯子放置字母的可能性有四种(A,B,C,D),第二个杯子有三种,因为第一个杯子已经确定了有一个字母,所以给第二个杯子三种选择,依次类推,第三个杯子有两种,第四个杯子有一种
\[ 4*3*2*1=24 \]
所以一共有24种可能性。但是题目中要求我们给出具体的排列,并且字符串中可能有重复的字母,大家能够懂以上排列组合的方式,我们就按照这个方式来给出具体的字母排列。

举例说明,假设题目中给的字符串是ABCD,我们可以采用第一个字母分别于四个位置的字母想交换的方式得出第一个位置的字母:
\[ ABCD,BACD,CBAD,DBCA \]
如上我们得出了四种,接下来我们需要考虑第二个位置的字母是什么,由于种类过多,此处仅用ABCD举例(余下的三种同理):
\[ ABCD,ACBD,ADCB \]
如上我们得出了三种,接下来再决定第四个位置的字母是什么,原因如上,我们仅用ABCD举例:
\[ ABCD,ABDC \]
如上我们得出了两种,再接下来我们就没有看的必要了,第四个位置就只有一种可能。

大家如果看懂上面的推导,接下来的代码部分应该是可以看懂了

function Permutation(str)
{
    // 判空操作
    if(str.length==0){return [];}
    const letters = str.split('');
    let res = [];
    function perm(list, start){
        if(start === letters.length-1){
            const str = list.join('');
            // 有可能会有重复字母,所以做查重处理
            if(!res.includes(str)){
                res.push(str);
            }
        }
        for(let i=start; i<list.length; i++){
            [list[i], list[start]] = [list[start], list[i]];
            perm(list, start+1);
            // 还原原有列表排序,以免影响后续计算
            [list[i], list[start]] = [list[start], list[i]];
        }
    }
    perm(letters, 0);
    // 按照字典序排序输出
    return res.sort((a,b)=>{return a>b?1:-1});
}

猜你喜欢

转载自www.cnblogs.com/Jacob98/p/12535464.html