字符串和数字的映射 康托展开

康托展开就是把一个字符串映射成一个数字

康托展开的公式是 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 其中,ai为当前未出现的元素中是排在第几个(从0开始)。

注意是从0开始的,理解的话,先ABCD A在ABCD里是第0个所以a4=0,接着把A去掉,B在BCD里面是第0个所以a3=0,接着把B去掉,依次都为0

 1 int fac[] = {1,1,2,6,24,120,720,5040,40320,362880};// factorial阶乘
 2 //康托展开
 3 int cantor(char arr[])
 4 {
 5     int res = 0;
 6     bool vis[10] = {0};
 7     for(int i = 0 ; i < 9; i++)
 8     {
 9         int x = s[i] -'0', y = 0;
10         for(int j = 1; j < x; j++)//这步的实质就是找x在序列中是第几大
11         //如果前面出现过比x大的数,那个数一定比x大所以扫不到,如果前面出现比它小的数,那个数已经被标记为1了
12             if(!vis[j])
13                 y++;
14         res += y*fac[8-i];
15         vis[x] = true;
16     }
17     return res;
18 }

 康托逆展,用辗转相除法实现,先把康托展示的值除n-1!,除数为an,余数继续执行

通过康托逆展开生成全排列

  如果已知 s = ["A", "B", "C", "D"],X(s1) = 20,能否推出 s1 = ["D", "B", "A", "C"] 呢?
  因为已知 X(s1) = a4*3! + a3*2! + a2*1! + a1*0! = 20,所以问题变成由 20 能否唯一地映射出一组 a4、a3、a2、a1?如果不考虑 ai 的取值范围,有
  3*3! + 1*2! + 0*1! + 0*0! = 20
  2*3! + 4*2! + 0*1! + 0*0! = 20
  1*3! + 7*2! + 0*1! + 0*0! = 20
  0*3! + 10*2! + 0*1! + 0*0! = 20
  0*3! + 0*2! + 20*1! + 0*0! = 20
  等等。但是满足 0 <= ai <= n-1 的只有第一组。可以使用辗转相除的方法得到 ai,如下图所示:

posted @ 2016-08-05 10:19  lyn流光  阅读(1768)  评论(0)    收藏  举报