字符串的第n个排列的算法

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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kgduu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值