剑指offer JS题解 (27)字符串的排列

题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。

输入规范

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

示例

输入:s = “abc”
输出:[“abc”,“acb”,“bac”,“bca”,“cab”,“cba”]

解题思路

我在leetcode上做这道题的时候,是用的解法三,是递归回溯的方法。实际上全排列就是一个决策问题,刻画成一颗树的话,就是每一层要选择什么字符,最后能得到多少种不同的路径。并且,由于字符是可能重复的,所以还需要进行树的剪枝。具体思路如下:

1、从首层开始递归,逐位固定,首先判断是否到达最后一位,如果是,说明所有的位已经固定好了,这时拼接字符串,加入到结果数组当中;否则进入第二步;
2、新建一个集合,用于剪枝。对当前位及剩余位的所有字符进行循环,取出之中的一位作为当前位的选择,假如集合中已经存在相同的选择,则进入下一轮循环去选择下一位;否则将加入集合,并且与当前位进行交换,再进入下一层的递归。
3、等到子层的递归结束后,需要将之前交换的两个位置复原,并进入下一轮,选择其他字符分支进行递归。

然而在leetcode上做这道题的时候,没有字典序的限制,对输出并不严格,我在牛客网上做这道题先是用了同样的思路,然后对最终结果进行了排序,才得到了正确结果。显然,这样是比较花时间的。结果出现非字典序,大概是因为交换的缘故,于是我参考了另一种回溯解法(解法一)。

还有一种剑指offer上比较容易理解的递归解法(解法二),也可以参考,但和解法三一样,需要对结果排序:

1、把字符串分为两部分:第一部分为第一个字符,第二部分为第一个字符以后的字符串。
2、然后接下来求后面那部分的全排列。
3、再将第一个字符与后面的那部分字符逐个交换

Code

// 解法一,完美的递归回溯
function Permutation(str)
{
    // write code here
    if(str.length==0) return [];
    //pStr用于存储结果字符串
    const pStr='';
    let [arr,res]=[str.split(''),[]];
    res=permutate(arr,pStr,res);
    return res;
}
function permutate(arr,pStr,res){
    if(arr.length==0)
        return res.push(pStr);
    const isRepeated=new Set();
    for(let i=0;i<arr.length;i++){
        if(!isRepeated.has(arr[i])){
            //删除当前位,并用char保存arr[i]
            const char=arr.splice(i,1)[0];
            pStr+=char;
            permutate(arr,pStr,res);
            //还原字符串数组
            arr.splice(i,0,char);
            pStr=pStr.slice(0,pStr.length-1);
            isRepeated.add(char);
        }
    }
    return res;
}

// 解法二,类似于解法三
function Permutation2(str) {
  let res = [];
  if (str.length <= 0) return res;
  arr = str.split(''); // 将字符串转化为字符数组
  res = permutate2(arr, 0, res);
  res = [...new Set(res)]; // 去重
  res.sort(); // 排序
  return res;
}
function permutate2(arr, index, res) {
  if (arr.length === index) {
    let s = '';
    for (let i = 0; i < arr.length; i++) {
      s += arr[i];
    }
    return res.push(s);
  }
  for (let i = index; i < arr.length; i++) {
    [arr[index], arr[i]] = [arr[i], arr[index]]; // 交换
    permutate2(arr, index + 1, res);
    [arr[index], arr[i]] = [arr[i], arr[index]]; // 交换
  }

  return res;
}

// 解法三

function Permutation(str)
{
    // write code here
    let [c,res]=[str.split(''),[]];
    function dfs(x){
        if(x==c.length-1){
            res.push(c.join(''));
            return;
        }
        let dic=new Set();
        for(let i=x;i<c.length;i++){
            if(dic.has(c[i]))
                continue;
            dic.add(c[i]);
            [c[i],c[x]]=[c[x],c[i]];
            dfs(x+1);
            [c[i],c[x]]=[c[x],c[i]];
        }
    }
    dfs(0);
    res.sort();
    return res;
}

运行环境:JavaScript (V8 6.0.0)
运行时间:26ms
占用内存:6944k

猜你喜欢

转载自blog.csdn.net/qq_40340478/article/details/106226018