引言
早年,我发现了一种可以用一个整数表示一个序列的数学方法。
下表是3个数字的全排列,有6种情况,编号0到5。
编号 | 序列 |
---|---|
0 | 0,1,2 |
1 | 0,2,1 |
2 | 1,0,2 |
3 | 1,2,0 |
4 | 2,0,1 |
5 | 2,1,0 |
编码
下面介绍如何从序列计算出编号。以2,1,3,0为例。
2 1 3 0 2+0*4=2
1 2 0 1+2*3=7
1 0 1+7*2=15
0 0+15*1=15
首先,取最左的数字2,得到了2。剩下1,3,0。把大于2的数字减1,得到1,2,0。
其次,取最左的数字1,把上一步得到的2,乘以当前的数字个数3,再和1相加,得到7。剩下2,0,把大于1的数字减1,得到1,0。
再次,取最左的数字1,把上一步得到的7,乘以当前的数字个数2,再和1相加,得到15。剩下0,把大于1的数字减1,得到0。
最后,取最左的数字0,把上一步得到的15,乘以当前的数字个数1,再和0相中,得到15。
序列有几个数字,就作几次运算。
用同样的算法,把0,1,2,3共4个数字的全排列24种序列进行计算,刚好得到0至23共24个整数。
解码
那么,如何反算编号,还原出序列呢?以15还原出0~3共4个整数为例。
0
15/2=7...1 1 1 0
7/3=2....1 1 1 2 0
2/4=0....2 2 2 1 3 0
首先,固定给序列加上数字0。
其次,当前序列的个数1加上固定1得到2。15除以2商7余1,把余数1加到序列的左边,得到1,0。
再次,和上一步同样的算法,上一步的商7除以3商2余1,把序列中比1大的数字加1,再把1加到序列的左边,得到 1,2,0
最后,和上一步同样的算法,上一步的商2除以4商0余2,把序列中比2大的数字加1,再把2加到序列的左边,得到 2,1,3,0
要还原的序列有几个数字,就作几次运算。最后一次运算的商肯定是0。
用同样的算法,把0至23共24个数字进行计算,刚好得到全排列24种序列。
优点
这种算法有什么优点
- 一个整数,就能存储一个序列,非常节约了存储空间。
多个数字变一个 - 不同的序列,换算成的整数是连续的,还是节约存储空间。
这一个数字还很小 - 支持任意个数字的序列,有普通性。
上述的例子是4个数的序列,这种算法支持任意的个数。当然,不能少于1个。
限制
这种算法有什么限制
- 整数必须是从0开始,并且是连续的,即是0~n,共n+1个数。不是这种情况,得先转化成这种情况。
- 必须是整数,不支持字符,除非能换算成整数
数字的个数
前面的例子,要还原出序列,即需要数字15,也需要知道序列的个数,即数字4。所以,完整来讲不是一个数,而是两个数。
在很多场景下,序列的个数是事先约好的,是固定的,所以,又变成了一个数。
由来
记得在2010年,就向朋友介绍过这种算法。这位朋友长期在国外,最近回国可能是探亲。令我想起这种算法,所以编理成文。
这种算法不是在哪里抄的,或借鉴的,是我自个儿琢磨的。目前推算,应该是2005至2010之间想出来的。