原题:排列序列
思路:找到规律,拆解独立步骤,递归
思路 观察题目我们可以看出是按照数字从小到大的顺序排列组合的
所以不妨拆分成按照位置求每一位
举个例子:
1 2 3 4 5 6 7 123 132 213 231 312 321
稍微观察就可以找到一个规律,只看第一位,第 k 个数为当前未使用数的第 (k ÷ 其余位组合种类) 个数 比如 k = 4
,那么就是 4 ÷ 2(两位数的组合数) = 2(未使用数中的第二个)
,因为没有任何数字被使用过,所以第一位数是 2
1. 初始化 我们求组合数会用到阶乘,同时还需要跳过已经使用过的数字
从而需要使用两张哈希表 calMap
、resultMap
1 2 3 4 const calMap = {};const resultMap = {};
同时准备一个能缓存结果的阶乘函数 calNum
1 2 3 4 5 6 7 8 9 10 11 12 13 function calNum (n ) { if (calMap[n] !== undefined ) return calMap[n]; let res = 1 ; let i = 1 ; while (i <= n) { res *= i; calMap[n] = res; i++; } return res; }
2. 实现找到当前位数字的方法
计算是第几个数
1 2 let step = n === 1 ? 1 : Math .ceil (k / calNum (n - 1 ));
进入循环寻找未使用的第 step
个数字
这里用到两个指针,i
表示数字,j
记录步数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 for (let i = 0 , j = 0 ; ; ) { if (j === step) { resultMap[i] = true ; if (n === 1 ) { return i.toString (); } else { return i.toString () + deal (n - 1 , k % calNum (n - 1 ) || calNum (n - 1 )); } } i++; if (!resultMap[i]) { j++; } }
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 var getPermutation = function (n, k ) { const calMap = {}; const resultMap = {}; function calNum (n ) { if (calMap[n] !== undefined ) return calMap[n]; let res = 1 ; let i = 1 ; while (i <= n) { res *= i; calMap[n] = res; i++; } return res; } function deal (n, k ) { let step = n === 1 ? 1 : Math .ceil (k / calNum (n - 1 )); for (let i = 0 , j = 0 ; ; ) { if (j === step) { resultMap[i] = true ; if (n === 1 ) { return i.toString (); } else { return i.toString () + deal (n - 1 , k % calNum (n - 1 ) || calNum (n - 1 )); } } i++; if (!resultMap[i]) { j++; } } } return deal (n, k); };