LeetCode60. 第k个排列

LeetCode60. 第k个排列

题目说明

给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:

“123”
“132”
“213”
“231”
“312”
“321”
给定 n 和 k,返回第 k 个排列。

说明:
给定 n 的范围是 [1, 9]。
给定 k 的范围是[1, n!]。

示例 1:
输入: n = 3, k = 3
输出: “213”

示例 2:
输入: n = 4, k = 9
输出: “2314”

题目解析

一般这种情况,需要将例子扩大范围,从而找到更多更明显的规律。一开始和参考博客的想法是差不多的,但是是直接寻找K值,而参考博客的做法是将K值减一,其实差不多,只是不需要多些处理。我们这里用例子 n=4,k=15为例。
首先,列出所有情况:
1234
1243
1324
1342
1423
1432
/*******
2134
2143
2314
2341
2413
2431
/*******
3124
3142
3214 --> here
3241
3412
3421
/*******
4123
4132
4213
4231
4312
4321
可以看到,首先第一位是按照 (n-1)!=(4-1)!=6个分组长度来区分,然后第二位是按照(3-1)!=2的分组长度区分,因此我们先定义一个存放 0-(n-1)阶乘结果的数组[1,1,2,6…]。这里我们先将k-1得到14。然后定义我们需要定位的数组"123456789"(下标从0开始)。按照这个例子,定位数组是"1234"

  1. 计算 14/3! = 2 余 2,其中结果2是结果在最高位的定位,找到定位数组下标为2的数字,为3,存入结果数组 3。下一次定位时已经不包含这个数,因此我们需要将其在定位数组中去除。得到新的定位数组"124"。余数2则是其在以3开头的分组中的位置(下标0开始)。但是我们无法直接取到这个数,所以继续推。
  2. 我们可以看到接下来可以按照2个来进行分组,也即(3-1)!=2,存入结果数组 32。这里有一个技巧点,就是要利用余数来除以新的分组长度。也即上一步得到的 2/2! =1 余 0,其中得到的结果1是其在新的最高位的定位,也即"124"中的2,所以第二位数是2。得到新的定位数组"14"
  3. 按照这个规律,余数 0/1! = 0 余 0,得到的结果,在最高位的位置为0,也即为"1"。存入结果数组 321得到新的定位数组"4"
  4. 余数 0/0! = 0 余 0,得到结果在新的最高位的位置为0,也即"4"存入结果数组 3214
  5. 综上,得到最终的结果 3214。

代码

class Solution {
public:
    string getPermutation(int n, int k) {
        string res;
        string num = "123456789";
        vector<int> f(n, 1);  // 数组f下标从中存放 0-(n-1)阶乘结果
        for (int i = 1; i < n; ++i)
        {
            f[i] = f[i - 1] * i;  // 1,2,6...
        }   
        k--;   // 将寻找的第k个排列转换为数组下标
        for (int i = n; i >= 1; --i) {  //循环将1-n的每个数取出
            int j = k / f[i - 1];
            k %= f[i - 1];
            res.push_back(num[j]);
            num.erase(j, 1); // erase(pos,n); 删除从pos开始的n个字符,从0开始计数
        }
        return res;
    }
};

参考:https://www.cnblogs.com/grandyang/p/4358678.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值