LeetCode 60. 第k个排列

LeetCode 60. 第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”

分析

由于以前做过 leetcode 31 下一个排序,所以首先想到直接调用此函数k次,就可以生成第k个排序。但是似乎有点满。考虑数学方法,假如有n个数,那么第一个数是(0,n)之间任意数的概率都是n!/n,即(n-1)!,
用(k-1)/(n-1)!得到的结果即是当前需要的插入的数字在备选区的位置。
处理后将当前数移除备选区,依次以相同方法处理第二位至最后一位即可。

依次生成

class Solution {
public:
    string getPermutation(int n, int k) {
        string res = "";
        for(int i = 1; i <= n; i++){
            res += '0' + i;
        }
        for(int i = 0; i < k - 1; i++){
            res = nextPermutation(res);
        }
        return res;
    }
    string nextPermutation(string s){
        int len  = s.size();
        int k = -1, l = 0;
        
        for(int i = len - 2; i >= 0; i--){
            if(s[i] < s[i + 1]){
                k = i;
                break;
            }
        }
        if(k == -1){
            reverse(s.begin(), s.end());
            return s;
        }
        for(int i = len - 1; i >= 0; i--){
            if(s[i] > s[k]){
                l = i;
                break;
            }
        }
        swap(s[k], s[l]);
        
        reverse(s.begin() + k + 1, s.end());
        return s;
    }
};

数学方法

class Solution {
public:
    string getPermutation(int n, int k) {
        string res;
        vector<char> temp(n);
        for(int i = 0; i < n; i++){
            temp[i] = '1' + i;
        }
        for(int i = 0; i < n; i++){
            int f = helper(n - i - 1);
            int t = (k -1 ) / f;
            k -= f * t;
            res += temp[t];
            temp.erase(temp.begin() + t);
        }
        return res;
    }
    int helper(int x){
        if(x <= 1){
            return 1;
        }else{
            return x * helper(x - 1);
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值