[Alg]排列与反序

排列与反序


作者:屎壳郎 miaosg01@163.com

日期:June 2021

版次:初版


每个排列都有相对应的唯一的反序表,根据反序表能生成唯一的排列。这两者之间有一一对应关系。那么我们如何在两者之间转换呢?即,已知排列,如何求它的反序表;反过来,知道一个反序表,如何生成相对应的排列呢?

1. 如何根据排列求其反序表

根据反序的定义,已知排列 ( R 1 , R 2 , … , R n ) (R_1, R_2,\ldots, R_n) (R1,R2,,Rn),其中 R k R_k Rk的反序 b R k b_{R_k} bRk为:位于 R k R_k Rk之前且大于 R k R_k Rk的数的个数。自然而然的,我们就想到了遍历统计,即 R k R_k Rk与所有 R k R_k Rk之前的项两两比较,统计出比 R k R_k Rk大的数即可。但这需要 n ( n − 1 ) 2 {n(n-1)\over2} 2n(n1)次比较,需要进行 n ( n − 1 ) 4 {n(n-1)\over4} 4n(n1)次统计(均值,见拆分数),时间复杂度 O ( n 2 ) O(n^2) O(n2)

那还有没有更高端大气上档次的算法呢?下面介绍一种时间复杂度为 O ( n lg ⁡ n ) O(n\lg n) O(nlgn)算法。按二进制位进行统计,有点类似于基数排序,可参照基数排序来帮助理解。

以排列(5 9 1 8 2 6 4 7 3)为例,把它表示为二进制代码:
5   ( 0   1   0   1 ) 2 5\ (0\ 1\ 0\ 1)_2 5 (0 1 0 1)2
9   ( 1   0   0   1 ) 2 9\ (1\ 0\ 0\ 1)_2 9 (1 0 0 1)2
1   ( 0   0   0   1 ) 2 1\ (0\ 0\ 0\ 1)_2 1 (0 0 0 1)2
8   ( 1   0   0   0 ) 2 8\ (1\ 0\ 0\ 0)_2 8 (1 0 0 0)2
2   ( 0   0   1   0 ) 2 2\ (0\ 0\ 1\ 0)_2 2 (0 0 1 0)2
6   ( 0   1   1   0 ) 2 6\ (0\ 1\ 1\ 0)_2 6 (0 1 1 0)2
4   ( 0   1   0   0 ) 2 4\ (0\ 1\ 0\ 0)_2 4 (0 1 0 0)2
7   ( 0   1   1   1 ) 2 7\ (0\ 1\ 1\ 1)_2 7 (0 1 1 1)2
3   ( 0   0   1   1 ) 2 3\ (0\ 0\ 1\ 1)_2 3 (0 0 1 1)2

我们从最高位开始比较,为方便我们单独取出最高位:(0 1 0 1 0 0 0 0 0),这样数据就划分成了两类,最高位为1的大数群体和最高位为0的小数群体。设置一个变量 x 0 x_0 x0用来记录到当前位置为止1出现的次数(当前位置前面有多少个1的大数)。然后从头到尾遍历排列,遇到1就对变量 x 0 x_0 x0加1,遇到0就对其对应的反序加 x 0 x_0 x0。还是以例子说明:

x 0 ← 0 x_0\gets0 x00 ( b 1 , b 2 , … , b n ) ← ( 0 , 0 , … , 0 ) (b_1, b_2, \ldots, b_n)\gets(0,0,\ldots,0) (b1,b2,,bn)(0,0,,0),从左到右执行如下:

  • 最高位(原始项),执行动作;
  • 0(5) 遇到0, b 5 ← b 5 + x 0 b_5\gets b_5+x_0 b5b5+x0;
  • 1(9) 遇到1, 把 x 0 x_0 x0加1, x 0 ← x 0 + 1 x_0\gets x_0+1 x
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值