线性时间复杂度递推求 0 到 2的幂次-1 的二进制翻转

如何定义一个数的二进制翻转(后的数)?
也就是

[reverse(quad (dots x_3x_2x_1x_0)_2 quad) = ; ? ]


直观地理解, 就是把一个数的二进制表示的最后一位和第一位交换、倒数第二位和第二位交换……
但是就如上面的例子, 知道了一个数二进制表示的最后一位, 那么这个数的二进制表示下的第一位是什么?不规定第一位, 翻转后的数是确定且唯一的吗?

显然平常求一个数的二进制翻转, 是要求一个具体的数。
要求具体的数, 就要规定一个数的 “二进制位数”, 意即这个数在二进制表示下的第一位是从右到左第几位。


本文介绍的递推方法, 可以求二进制位数一定时的所有数的二进制翻转(显然有限的二进制位数只能表示有限个数, 即 (x) 位二进制只能表示 ([0, 2^x-1])(2^x) 个数)。

(由于不是我想出来的所以只给方法啦qwq)

具体方法是将一个二进制数 ((x_n dots x_0)_2) 看作 ((x_n dots x_1)_2)((x_0)_2)
首尾相接拼起来的两个数, 于是

[reverse(quad (x_n dots x_0)_2 quad) ]

[= x_0 接上 ; reverse(quad (x_n dots x_1)_2 quad) ]

(下面式子里的 (reverse(quad (x_n dots x_1)_2 quad)) 是在二进制位数为 (n) 意义下的翻转)

但是递推到 ((x_n dots x_0)_2) 时, 手上只有 ((0:x_n dots x_1)_2)
(即(x_n dots x_1)_2)在二进制位数为 (n+1) 意义下的表示)
的二进制翻转, 怎么办?

其实操作一番就是了, 具体看代码就好啦。

最后一点就是由于 (x_0) 是二进制位数为 (n) 意义下的最后一位, 所以其必定被翻转到二进制位数为 (n) 意义下的第一位(帮助理解代码)。

for(int i=0; i<lim; ++i) { // lim是二的幂次
//这段代码是求 0 ~ lim-1 在二进制位数为 log_2(lim)-1 意义下的二进制翻转
//其中, 数 i 的翻转被储存在 re[i] 里
	re[i] = (re[i>>1]>>1)|((i&1)?lim>>1:0);
}
原文地址:https://www.cnblogs.com/tztqwq/p/12774894.html