Во-первых, пусть k будет наименьшей степенью 2, большей или равной sqrt (n).k по-прежнему равно O (sqrt (n)), поэтому это не изменит сложности.
Чтобы построить полную таблицу k по k, мы создадим ее по одной строке за раз.
МыНачните с 0-й строки: это легко, потому что 0 xor j = j.
for i in xrange(k):
result[0][i] = i
Далее мы перебираем строки в порядке с серым кодом.Серый код - это способ подсчета каждого числа от 0 до единицы меньше степени 2 путем изменения одного бита за раз.
Из-за свойства серого кода мы меняем строкучисло на 1 бит, поэтому мы легко вычисляем новую строку из старой, поскольку xors будет меняться только на 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
Наконец, хитрый бит:считая в серых кодах.Из википедии мы можем прочитать, что простой серый код может быть получен путем вычисления 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), но это нормально, так как мы не используем его во внутреннем цикле основной функции.