求第k个排列。
刚开始按照一个排列一个排列的求,超时。
于是演算了一下,发下有数学规律,其实就是康托解码。
康托展开:全排列到一个自然数的双射
X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!
ai为整数,并且0<=ai<i(1<=i<=n)
适用范围:没有重复元素的全排列
全排列的解码
如何找出第16个(按字典序的){1,2,3,4,5}的全排列?
1. 首先用16-1得到15
2. 用15去除4! 得到0余15
3. 用15去除3! 得到2余3
4. 用3去除2! 得到1余1
5. 用1去除1! 得到1余0
有0个数比它小的数是1,所以第一位是1
有2个数比它小的数是3,但1已经在之前出现过了所以是4
有1个数比它小的数是2,但1已经在之前出现过了所以是3
有1个数比它小的数是2,但1,3,4都出现过了所以是5
最后一个数只能是2
所以排列为1 4 3 5 2
class Solution{ public: string getPermutation(int n, int k) { //get fractial vector<int> fractial; fractial.push_back(1); for(int i = 1;i<n;i++) { fractial.push_back(fractial[i-1]*(i+1)); } //to mark if this digit selected ,true means can be selected, false means already selected. vector<bool> allnum; for(int i = 0; i <=n; i++) allnum.push_back(true); int ChuShu = k - 1, YuShu = 0; string ans; int weishu = 0; while(weishu<n) { int _num_i; int place; if(weishu == n-1) // the last digit _num_i = select(allnum,1); else { YuShu = ChuShu % fractial[n-2-weishu]; place = ChuShu / fractial[n-2-weishu]; _num_i = select(allnum,place + 1 ); } ChuShu = YuShu; weishu ++; char ch = '3' - 3 + _num_i; ans += ch; } return ans; } int select(vector<bool> &allnum,int place) { int i = 1; while(place) { if(allnum[i] == true) { place--; if(place == 0) break; } i++; } allnum[i] = false; return i; } }; int main() { class Solution myS; cout<<myS.getPermutation(5,16); return 0; }