LeetCode(60): Permutation Sequence (C++)

一、题目

The set [1,2,3,…,n] contains a total of n! unique permutations.

By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

Given n and k, return the kth permutation sequence.

二、分析

    此题可用暴力枚举,即调用 k - 1 次的 std::next_permutation() 或者是在 LeetCode(31): Next Permutation 所实现的函数,但这样做求出了前 k  个所有排列,会超时,我们只需要求出第 k 个即可。

    为了能更清楚地说明接下来的算法,我们先来看对于 n = 3 时,所有排列的特点。


  • 可分为 n = 3 组,每组有 (n - 1)! 即 (3 - 1)! 个排列;
  • 第 m 组(其中, 1 ≤ m ≤ n)中,第一个数为所有数字升序排列的第 m 个数,如:第 3 组第一个数为 [1, 2, 3] 的第三个数,即3;
  • 第 m 组的第一个排列,即总的第 (m - 1) * (n - 1)! + 1 个排列,第一个数之后,为升序排列;
  • 第 m 组的最后一个排列,即总的第 m * (n - 1)! 个排列,第一个数之后,为降序排列;

    有此规律,我们便可递归求解,即总的 n 个数的第 k 个排列,可以通过确定第一个数之后,求剩下的 (n - 1) 个数的第 k - m * (n - 1)! 个排列,其中,m = floor(k / (n - 1)!)。

三、代码实现

class Solution {
private:
    long fact(int n){
        if(n == 0){
            return 1;
        }else{
            return n * fact(n - 1);
        }
    }
    
    void permute(string& str, int start, int k){
        if(k == 1 || k == 0){
            return;
        }
        
        const int len = str.size();
        
        if(k == fact(len - start)){
            sort(str.begin() + start, str.end(), greater<char>());
            return;
        }else{
            int tmp = fact(len - start - 1);
            int num = k / tmp;
            
            k -= num * tmp;
            
            if(k == 0){
                swap(str[start], str[start + num - 1]);
                sort(str.begin() + start + 1, str.end(), greater<char>());
            }else{
                swap(str[start], str[start + num]);
                sort(str.begin() + start + 1, str.end());
            }
            
            permute(str, start + 1, k);
        }
        
        
    }
    
public:
    string getPermutation(int n, int k) {
        string s;
        int sum = 0;
        
        s.resize(n);
        for_each(s.begin(), s.end(), [&sum](char& c){ c = '0' + (++sum); });
        
        permute(s, 0, k);
        
        return s;
    }
};


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值