coverPiccoverPic

Leetcode 60 排列序列

思路

Leetcode60 排列序列这是一个排列组合的问题。这个思路写出来大概也是源于想用模拟的方法解决这个问题,实际上我们可以说是采用了回溯/遍历的写法。

①众所周知,nn个字符进行排列有total=n!total=n!种排列,每个首字符平均有per=total/nper=total/n种情况,那么可以根据排列的字符序号kk确定首字符是未排列字符中的第几个,即index=Math.ceil(k/per)index = Math.ceil(k / per),就是k/perk/per向上取整。

②拿到了首字符的序号indexindex之后,我们来看未排列的字符集,字典序(从小到大)遍历字符集,找到第indexindex个未访问的字符,就是当前的首字符firstfirst了。

③第二个字符的话,考虑firstfirst开头的字符串,这时候,total=(n1)!total=(n-1)!per=total/(n1)per=total/(n-1)k=(kmodlevel)levelk=(k \mod level) \| level,就是减去排在前面的字符排列数。参照第①步,就可以找出第二个字符了,以此类推,直至找到所有字符。

对于存储字符集,这里为了节省空间采用了位运算的方法,需要2n2^n位,1<=n<=91<=n<=9,在JS/TS里面一个number类型就够用了。

再来点好玩的,这里计算阶乘使用了一种近似算法,精度高达10410^{-4}(虽然在本题目的数据量上运算速度并没有什么显著差异)。

复杂度

  • 时间复杂度: O(n2)O(n^2),输出每一位字符需要O(n)O(n)复杂度,期间遍历字符集需要O(n)O(n)复杂度。

  • 空间复杂度: O(n)O(n),用于存储每一个字符是否被访问过

  • 时间:64 ms,击败:92.86%;内存:41.9 MB,击败:100%

Code

typescript
  1. function getPermutation(n: number, k: number): string {
  2. const z = n + 1
  3. let total = Math.round(
  4. (2 * Math.PI / z) ** 0.5
  5. * (z / Math.E * (z * Math.sinh(1/z) + 1 / ( 810 * z ** 6)) ** 0.5) ** z
  6. )
  7. let visit = 0
  8. const getNum = (index: number) => {
  9. let ans = 0, count = 0
  10. do {
  11. if ((visit & (1 << ans++)) === 0) {
  12. count++
  13. }
  14. } while (count < index)
  15. visit = visit | (1 << ans - 1)
  16. return ans
  17. }
  18. let ans = '', rem = k
  19. for (let i = 0; i < n; i++) {
  20. total = total / (i === 0 ? 1 : n - i + 1)
  21. const per = total / (n - i)
  22. const index = Math.ceil(rem / per)
  23. rem = rem % per || per
  24. const num = getNum(index)
  25. ans += num + ''
  26. }
  27. return ans
  28. };
5 条评论未登录用户
Ctrl or + Enter 评论
呜呜
好耶~(≧∇≦)/
2 years agoReply to
尊嘟可爱蓝莓
喵喵喵
2 years agoReply to
KokoroAme
喵喵喵
2 years agoReply to
尊嘟可爱蓝莓
好耶
2 years agoReply to
KokoroAme
贴贴
2 years agoReply to
© 2023-2025 LittleRangiferTarandus, All rights reserved.
🌸 Run