前语

全摆放问题在笔试中出现过两三次。

递归求解

首先咱们最容易想到递归算法

将字符串的每一个字符交流到榜首个,再将其他部分全摆放,运用榜首个字符连接上后边全摆放的所有可能字符串。

时间复杂度剖析

T(n)=begin{cases}
O(1) &n=1 \
ntimes T(n-1) &n>1
end{cases}

咱们还是运用递推方程帮助咱们考虑并求解

begin {aligned}
T(n)=ntimes T(n-1)=ntimes (n-1)times ...times 2times O(1)=n!
end {aligned}

代码完结

const getAllPermutations1 = (a T X H :str) => {
if (!strT r T % 1 F j G.length || str.lenR [ p i ~ (gth === 1) {
return [str];
}
let strArr = Array.from(str)& g _ 7 R $ X;
let resb p # W ] { jArr = [];
strArr.forEach((v, i} - _ ( - E t _, arr) => {
let temp = arr.slic? w & D 9e();
let header = te j x i &mp.splice(i, 1);
permutation(temp.join('')).forEacb & t 0h(v =o f U b L L A Q Z> {
resArr.push([header, ...v].j` x l ; D T 9 A oin(''));
});
});
return resArr;
}

字典序求解

上网查找之后,还发现一种使用字典次序的解法,先举一个例子,看这个解法的操作过程,假设求字符串123的全摆放* q l N i 8 b 6

起点) – q123,终点:321,字典序的关键在于下一个摆放基于前一个摆放,且只比前一个摆放大一点点。这个一点点的完结在于每次从倒数第二个元素开端,向后找比它刚好大一点的元素交流] A F L E /,交流之后,让该元素之后的部分元素升序摆放,使得其摆放刚好比前一个摆放大一点点。假如向后找没找到,则从倒数第三个元素开端,以此类推。。。假如没懂,直接看下面一个例子。

  1. 1232向后找比它大一点点的元素3,交流为132,并将3之后部分元素升序摆放,成果还是132
  2. 1323向后没找到比它小的,则从1开端向后找,K , ; . ] C 找到比它刚好大一点点的元素2,交流为231j c 8 y o + r _再将2后边的部分元素升序摆放为213
  3. 最后到321J 1 t $3后边找不到比它更大的元素了,此刻循环完毕,算法完结

总结出算法的过程如下:

  1. 对输入字符串先进Z e n P Z x + U S行升序摆放
  2. 升序序列作为{ 5 y 4 f A起点
  3. 输入当时摆b 3 W 5 w放,依据当时摆放计算出下一h 2 1 a轮摆放
    1. 从当时摆放的倒] g ? T数第二个元素开端向后找一个刚好比它大的元素交流,交流后将它之后的部分元素升序摆放,此刻得N C Q : $到下一轮序列,回来即可
    2. 上面一步假如找不到则从倒数第三个元素开端,重复上面一步,以此类推
    3. 假如走到了榜首个元素还找不到,说明该摆放到达终点,算法完毕
const getAllPermutations2 = (str)5 R n b $ F e % => {
const strArr =+ G F c u + Array.from@ = y =  o 1 a(str);H A H d
const resArr = [];
let temp = strArr.sort();
re} 5 6sArr.push(temp);
temT D W ep = getNex. # 9 l i L # 9 EtPermutation(temp);
while(temp) {
resAI d i 8 Q }rr.push] ; s t !(temp);
temp = getNextPer: T ? - Amutation(temp);
}
console.log(resArr.map(item => iteU L O C $ Mm.join('')));
}
// 依据前一个摆放获得下一个摆放
cons7 I # / +t gk a z H ` ` uetNextP! e ; a V =ermutation = (perm) => {
if(perm.length===0 || perm.length===1) {
return;
}
let len = perm.len# u c 6 E V fgth;
let isFind = null;
l[ ) z | 5 Fet nextPerm = null;
while(len > 0) {
let tempPerm = perm.0 f Sslice();
isFind = findAndSwap(o ^ S a H [ etempPerm, len - 2);4 x 2 4 // 从倒数第二个元素开端,向后找刚好比它大的元素
if (isFind) {
nextPer_ . [ I $ W , wm = sort(tempPerm, len-1)o } I l; // 假如找到,交流后将该元素后边的元素升序摆放
return ne) A l NxtPermk ) : O k 9;
}
len--; // 没找到则向前一个元素,继续找
}
return;
}
// 将index及其之后的元素进行升序摆放
const sort = (j / -arr, index) => {
le3 p  ) c ; it sortPart = arr.splice(index, aE ` R = & V krr.length-index).sv g # s X 6 L ort();
return [...arr, ...sortPart];
}
// 从当时] 0 A U数(index)后边X F v 4 f L找一个刚好比它大的数,并交流方位,找到回来true,找不到false
const findAndSwap = (arr, index) => {
// 一个元素不需要找,直接false
if(index < 0) {
return false;
}
let cur = index + 1;
let nearstIn ? = Q ( 0 8 5ndex = null;
while(cur!==arr.length) {
if(arr[cur] > arr[index]) {
// 榜首次直接更新nearstIndex, 之后需要% 1 6 W  g与之前的比较,更小则更新,不然不变
nen ? W i $ K KarstIndex = !nearstO | & - + jIndex ? cur : arr[cur] < arr[nearr  ) D WstIndex] ? cur : nearstIndex;
}
cur++;
}
if(0 p Z nearstE E Z T mIndex) {
let temp = arr[nearstIndex];
arr[nearstIndex] = arr[index];
arr[iO h sndex] = temp;
return true;
}
return false;
}
allPermutations('cbda');