排列序列
题目:
题目要求:
给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
1. "123" 2. "132" 3. "213" 4. "231" 5. "312" 6. "321"
给定 n 和 k,返回第 k 个排列。
示例
示例1:
输入:n = 3, k = 3
输出:"213"
示例2
输入:n = 4, k = 9
输出:"2314"
示例3
输入:n = 3, k = 1
输出:"123"
解题思路
这个解题思路纯属另辟蹊径,实际写下来极为麻烦,只是提供一种便于理解的思路以作参考。实质上还是回溯,利用数学方法,计算出全排列的数量,算出每一位数字可以有几种排列,最后依次检索出每一位应当输出的数字,最后合并即可。
我写的这段代码看注释下来比较容易理解,具体的可以参考注释,希望能给没有思路的人一些参考,但并不是一个很好的思路,实现下来也很麻烦,有冗余的地方,对读代码的人也不甚如人意,感觉写下来还有很多地方可以优化,还是没有题解答案来的精妙。
代码实现:
var getPermutation = function(n, k) {
if(n == 0) return ""
let arr = []
for(let item = 1;item <= n;item++){ //将全排列各元素放入数组
arr.push(item)
}
if(k == 1) return arr.join("") //k=1则为第一种排列,直接合并输出
let len = arr.length
let jc = arr.reduce((x,y) => x * y) //计算出共有几种排列情况
let index = 0
// 计算出目标排列顺序的第一个数字
if(k % Math.floor(jc / n) == 0)
index = Math.floor(k / Math.floor(jc / n)) - 1
else index = Math.floor(k / Math.floor(jc / n))
let temp = arr[index]
arr.splice(arr.indexOf(temp),1)
arr.unshift(temp) //将第一个数字放置首位
console.log(k - Math.floor(jc / n) * (Math.floor((k - 1) / Math.floor(jc / n))))
return dfs(arr,1,k - Math.floor(jc / n) * (Math.floor((k - 1) / Math.floor(jc / n)))).join("")
/*
依次传入存放各元素的数组(已排好第一位);从第几位开始仍需排序;以第一位数字开始第几个排列为题解
*/
};
var dfs = function(arr,cur,len){
if(len == 1) {
return arr
}
//len不为1时取排列好之后的继续排列,直到len=1,方法与上面一致
let nums = arr.slice(cur,arr.length)
let jc = 1
for(let i = 1;i <= nums.length;i++){
jc *= i
}
let index = 0
if(len % Math.floor(jc / nums.length) == 0) index = Math.floor((len) / Math.floor(jc / nums.length)) - 1
else index = Math.floor(len / Math.floor(jc / nums.length))
let temp = nums[index]
nums.splice(nums.indexOf(temp),1)
nums.unshift(temp)
arr = arr.slice(0,cur).concat(nums)
arr = dfs(arr,cur + 1,len - Math.floor(jc / nums.length) * (Math.floor((len - 1) / Math.floor(jc / nums.length))))
return arr
}