Permutation sequence

来源:互联网 发布:ioscydia软件源闪退 编辑:程序博客网 时间:2024/06/03 09:53

n个数的全排列,按照从下到大的顺序排列,问第k个位置的数是多少?

这个问题有几种方法,不过只有康托编码的时间复杂度是最低的。是O(n),简直凶残。

1.用next_permutation来求,这个也是leetcode上的一道题,就是求其下一个排列,然后对1234…n 运行k-1次 next_pernutation方法就能得到第k个数了

image

思想就是这样。

2.利用康托编码来求。

其实就是康托展开的逆过程。

康托展开用来求某个全排列数是第几小的数,也就是当这些数按顺序排时第几个数。

过程如下:比如求321 是 第几小的,可以这样来想:小于3的数有1和2 两个,首位确定之后后面两位有2!中情况,所以共有2*2!=4种。

小于2的数只有一个1,所以有1*1!=1种情况,最后一位是1,没有比一小的数,所以是0*0!=0

综上:小于321的数有4+1=5个,所以321是第六小的数。


逆过程就是已知这个数是第k个数,求这个数是多少,当然是知道n的值的。

第k个数就是有k-1个数比这个数小。

所以就是 k-1=an*(n-1)!+an-1*(n-2)!+....+a1*0!;


简单的,可以用暴力枚举法,调用k -1 次next_permutation()。
暴力枚举法把前k 个排列都求出来了,比较浪费,而我们只需要第k 个排列。


2.
利用康托编码的思路,假设有n 个不重复的元素,第k 个排列是a1; a2; a3; :::; an,那么a1 是
哪一个位置呢?
我们把a1 去掉,那么剩下的排列为a2; a3; :::; an, 共计n-1 个元素,n-1 个元素共有(n-1)!
个排列,于是就可以知道a1 = k/(n - 1)!。

同理,a2; a3; :::; an 的值推导如下:
k2 = k%(n - 1)!
a2 = k2/(n - 2)!
  
kn-1 = kn-2%2!
an-1 = kn-1/1!
an = 0


#include <iostream>using namespace std;#include <string>#include <vector>void nextPermutation(string & v){int end = v.size()-1;int  i = end ,k= end;while(i){if (v[i]>v[i-1])break;--i;}if (i>0){--i;while(v[k]<=v[i]) --k;swap(v[i],v[k]);reverse( v.begin()+i+1,  v.end() );}else{reverse( v.begin(),v.end() );}}// 调用k-1次Next Permutationstring getKthPermutation(int n ,int k){string s(n,'0');for ( int i =0; i<n;++i){s[i] += i+1;}int j = k-1;while (j--){nextPermutation( s);}return s;}int factorial (int n){int result = 1;for (int i = 1; i<= n;++i){result *= i;}return result ;}//康托编码template <typename sequence >sequence kth_Permutation(const sequence & seq ,int k){ const int n = seq.size(); sequence s(seq); sequence result; int base = factorial (n-1); --k;//康托编码是从0开始,即是s[0]下标是从0开始的,为一致,--k for (int i = n-1; i>0; k %= base, base /= i,--i) { auto a = next(s.begin(),k/base);//找到第n位上的数字在排列中的位置index,这样提取的数列中的index位 result.push_back(*a); //再push s.erase(a);//排列中数字不能重复,所以必须删除元素*a }result.push_back(s[0]);//,注意for循环是n-1到1,只push n-1个元素,所以还要push最后一个return result;}string getPermutation(int n , int k){string s(n,'0');string result;for ( int i =0; i<n;++i){s[i] += i+1;}return kth_Permutation(s, k);}int main(){int n = 5, k= 2;//test1 康托编码string s ;s = getPermutation(n, k);cout<<s;//test2 调用netx permutationstring s2;s2 = getKthPermutation(n,k);cout<<s2;return 0;}


0 0
原创粉丝点击