首先,设 k 为大于或等于 sqrt(n) 的 2 的最小幂。k 仍然是 O(sqrt(n)) 所以这不会改变复杂性。
为了构造完整的 k by k 表,我们一次构造一行。
我们从第 0 行开始:这很容易,因为 0 xor j = j。
for i in xrange(k):
result[0][i] = i
接下来,我们按格雷码顺序遍历行。格雷码是一种通过一次更改一位来计算从 0 到小于 2 的幂的每个数字的方法。
由于格雷码属性,我们将行号更改 1 位,因此我们可以轻松地从旧行计算新行,因为 xor 只会更改 1 位。
last = 0
for row in graycount(k):
if row == 0: continue
bit_to_change = find_changed_bit(last, row)
for i in xrange(k):
result[row][i] = flip_bit(result[last][i], bit_to_change))
last = row
我们需要一些函数来帮助我们。首先是一个找到第一个不同位的函数。
def find_changed_bit(a, b):
i = 1
while True:
if a % 2 != b % 2: return i
i *= 2
a //= 2
b //= 2
我们需要一个在 O(1) 时间内稍微改变的函数。
def flip_bit(a, bit):
thebit = (a // bit) % 2
if thebit:
return a - bit
else:
return a + bit
最后,棘手的一点:格雷码计数。从 wikipedia 中,我们可以读到一个简单的格雷码可以通过计算 xor(a, a // 2) 来获得。
def graycount(a):
for i in xrange(a):
yield slow_xor(a, a // 2)
def slow_xor(a, b):
result = 0
k = 1
while a or b:
result += k * (a % 2 == b % 2)
a //= 2
b //= 2
k *= 2
return result
请注意,slow_xor 是 O(a 和 b 中的位数),但这没关系,因为我们没有在 main 函数的内部循环中使用它。