Permutation Sequence

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.

Note: Given n will be between 1 and 9 inclusive.

1. 首先构造出来一个1 - n 的字符序列 p
2. 算出k的阶乘是多少 div
3. 如果k >= div ,那就是返回整个反转的p
4. 开始以下循环:
   div /= i; 
    pos = (k - 1) / div;
   这两行代码计算得到了pos,可以想一下,这时pos的含义是(k - 1)是div的多少倍, 只有经历一次完整的div变换,才能使得最高位换上一个新数, 现在经历了pos次,那么就是说第pos的字符被换到了当前最高位。
   k -= (pos * div) 
   得到还剩下多少个计数没有被处理
   p.erase(p.begin() + pos);
   因为地pos的元素已经知道会被放到当前最高位(ret当前的末尾),再下个循环处理k的时候这个元素已经不存在了,所以要剔除它。

在纸上画一遍1,2,3,4 第10个序列的过程会对这个过程有直观的理解。

1,2,3,4  (n = 4, k = 10)

第一次循环 
div /= 4   -> div = 6
pos = (k - 1) / 6  -> pos = 1
k -= (pos * div) -> k = 4
把2 放入 ret,从p剔除2

1,3,4     (ret = "2")

第二次循环:
div /= 3   -> div = 2
pos = (k - 1) / 2  -> pos = 1
k -= (pos * div) -> k = 2
把3 放入 ret,从p剔除3

1,4     (ret = "2 3")

第三次循环:
div /= 2   -> div = 1
pos = (k - 1) / 2  -> pos = 1
k -= (pos * div) -> k = 1
把4 放入 ret,从p剔除1

1 (ret= "2 3 4")

第四次循环:
div /= 1  -> div = 1
pos = (k - 1) / 1  -> pos = 0
k -= (pos * div) -> k = 1
把1 放入 ret,从p剔除1

ret = "2341"

从 “1234” 到 “2341“ ,k = 10

1234 -〉2134 ,消耗6次变换
2134 -> 2314, 消耗2次变换
2314-> 2341, 消耗1次变换

共消耗9次变换,位置从第一个变成第10个,这正是k= 10的要求。


class Solution {
public:
    string getPermutation(int n, int k) {
        // IMPORTANT: Please reset any member data you declared, as
        // the same Solution instance will be reused for each test case.
        if (k < 1) throw k;
        int div = 1;
        string p(n, '0');
        for (int i = 1; i <= n; i++) {
            p[i - 1] += i;
            div *= i;
        }
        
        
        if (k >= div) {
            reverse(p.begin(), p.end());
            return p;
        }
        
        string ret(n, ' ');
        auto rit = ret.begin();
        for (int i = n; i > 0; --i) {
            div /= i;
            int pos = (k - 1) / div;
            k -= (pos * div);
            *rit++ = p[pos];
            p.erase(p.begin() + pos);
        }
        return ret;
    }
};

    


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值