前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一天一大 lee(第k个排列)难度:中等-Day20200905

一天一大 lee(第k个排列)难度:中等-Day20200905

作者头像
前端小书童
发布2020-09-24 14:28:55
3050
发布2020-09-24 14:28:55
举报
文章被收录于专栏:前端小书童

题目:[1]

给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。

按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321" 给定 n 和 k,返回第 k 个排列。

说明:

  • 给定 n 的范围是 [1, 9]。
  • 给定 k 的范围是[1, n!]。

示例:

  1. 示例 1
代码语言:javascript
复制
输入: n = 3, k = 3
输出: "213"
  1. 示例 2
代码语言:javascript
复制
输入: n = 4, k = 9
输出: "2314"

抛砖引玉

抛砖引玉

思路

从1到n转换成从n到1,共有n的阶乘种组合;

分析排列过程:

  • 1开始的排列(n-1)的阶乘种组合
  • 2开始的排列(n-1)的阶乘种组合 ....
  • n开始的排列(n-1)的阶乘种组合

结合排列的顺序和k的大小,此时可以确定第一个字符

第二个字符:

  • 此时已知两个字符剩余字符的组合种类数为(n-2)的阶乘,n-1的阶乘除以n-1

第三个字符:

  • 此时已知三个字符剩余字符的组合种类数为(n-3)的阶乘,n-2的阶乘除以n-2

...

知道第k中排列或者最终n-x等于1得到最终排列

数学

代码语言:javascript
复制
/**
 * @param {number} n
 * @param {number} k
 * @return {string}
 */
var getPermutation = function (n, k) {
  let _result = '',
      nums = [], // 存放待排列元素
      factorial = 1; 
  for (let i = 1; i <= n; i++) {
    nums.push(i); 
    factorial = factorial * i;
  }
  // 计数和索引差1
  k= k-1;

  while (nums.length > 0) {
    factorial = factorial / nums.length; // 确定一个元素后,待排列的组合种类减少为(n-x)的阶乘
    let index = parseInt(k / factorial,10);     // 当前选择的数字的索引
    _result += nums[index];               // 加上当前选的数字
    nums.splice(index, 1);               // nums删去选的这个数字
    k = k % factorial;                   // 更新 k,
  }
  return _result;
}

回溯法

上面的数学法并没有生成具体的组合,都是通过确定元素后能得到的排列组合数来推导出第k个排列

更直观的方法是,枚举每个位置上可能的元素然后记录其对应的种类数,直到枚举到第k

递归选择要拼接的元素:

  • 参数:已选择的元素数组
  • 终止:所有元素均被选择
代码语言:javascript
复制
var getPermutation = function (n, k) {
  let used = new Map(),
    factorial = 1;
  for (let i = 1; i <= n; i++) {
    factorial = factorial * i;
  }

  function helper(temp) {

    let len = temp.length;

    if (len == n) return temp.join('');

    factorial = factorial / (n - len); // 待排列的元素存在的组合数

    for (let i = 1; i <= n; i++) {
      if (used.has(i)) continue; // 递归时忽略已经排列的元素

      if (k > factorial) { // 如果k大于剩余的组合数,则说明如果此位置排列i则排列完成不能有k种组合
        k = k - factorial; 
        continue; 
      }
      temp.push(i);        // 满足此位置选择i包含大于等于k中组合
      used.set(i, true);
      return helper(temp); // 继续选择i后面的元素
    }
  };

  return helper([]);
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-09-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端小书童 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 说明:
  • 示例:
  • 抛砖引玉
    • 数学
      • 回溯法
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档