题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。
输入规范
输入一个字符串,长度不超过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