1、next_permutation算法
直接使用STL中的
2、阶乘数制法
直接计算第n个排列,不需要找到所有的排列再找到第n个。
阶乘数系统使用阶乘值而不是数的幂来表示位值。
位值有
5!=120 4!=24 3!=6 2!=1 1!=1 0!=1
0阶位值总是为0,1阶位值可以是0或者1,2阶位值可以是0,1,2,依此类推。
前几个数用阶乘数系统表示如下
0 -> 0 = 0 * 0!
1 -> 10 = 1 * 1! + 0 * 0!
2->100 = 1 * 2! + 0 * 1! + 0 * 0!
3->110 = 1 * 2! + 1 * 1! + 0 * 0!
4 -> 200 = 2 * 2! + 0 * 1! + 0* 0!
5->210 = 2*2! + 1*1! +0*0!
6->1000=1*3! + 0*2!+0*1!+0*0!
7->1010=1*3!+0*2!+1*1!+0*0!
8->1100=1*3!+1*2!+0*1!+0*0!
9->1110
10->1200
字符串的第n个字典序排列与其阶乘数值表示有直接关系
以字符串abcd为例
0 abcd 6 bacd 12 cabd 18 dabc
1 abdc 7 badc 13 cadb 19 dacb
2 acbd 8 bcad 14 cbad 20 dbac
3 acdb 9 bcda 15 cbda 21 dbca
4 adbc 10 bdac 16 cdab 22 dcab
5 adcb 11 bdca 17 cdba 23 dcba
可以发现,第一个字符每6个变换一次(即3!),第二个字符每2个变换一次(即2!)
第三个字符第1个变换一次(即1!),第四个字符第1个变换一次(即0!)。可以使用这个关系来找到第n个排列。
用阶乘数值表示n后,考虑当中的每一个数,从源字符串中选取一个添加到生成的字符串中。如果需要找到abcd的第14个排列,用阶乘数值表示为2100
从第一个数字2开始,字符串是abcd,下标从0开始,取字符串中的第2个位置的字符,添加到输出字符串中。输出字符串和源字符串变为
Output String
c abd
2 012
下一个数字是1,此时字符串是abd.取字符串中下标为1的字符添加到输出字符串中。输出字符串和源字符串变为
Output String
cb ad
21 01
下一个数字是0,此时字符串是ad,取字符串中下标为0的字符添加到输出字符串中。输出字符串和源字符串变为
Output String
cba d
210 0
下一个数字是0,此时字符串是ad,取字符串中下标为0的字符添加到输出字符串中。输出字符串和源字符串变为
Output String
cbad ''
2100
为了将给定的数转换为阶乘数值表示的数,连续用1,2,3,4,...数除以给定的数,直到商为0.每一步中的余数构成了阶乘表示。
代码如下:
vector<int> convertFactorial(ll n, int len)
{
vector<int> ans;
ll num = 1;
while (n != 0) {
int remaider = n % num;
ans.push_back(remaider);
n = n / num;
++num;
}
if (ans.size() < len) {
for (int i = ans.size(); i < len; ++i) {
ans.push_back(0);
}
}
reverse(ans.begin(), ans.end());
return ans;
}
char getUnusedCh(const string& src, int pos, vector<bool>& unused)
{
int cnt = 0;
for (size_t i = 0; i < unused.size(); ++i) {
if (!unused[i]) {
if (cnt == pos) {
unused[i] = true;
return src[i];
}
++cnt;
}
}
return ' ';
}
string getPermutation(const string& src, ll n)
{
vector<int> factorial = convertFactorial(n, src.length());
string ans;
vector<bool> unused(src.length(), false);
for (vector<int>::const_iterator it = factorial.begin(); it != factorial.end(); it++) {
int pos = *it;
char ch = getUnusedCh(src, pos, unused);
ans.push_back(ch);
}
return ans;
}