我想计算从0到(n)^ {1/2} - 1的数字的XOR,每个数字从0到(n)^ {1/2} - 1。 我希望在O(n)时间内完成此操作,并且无法使用XOR,OR和AND操作。
如果我知道X和Y的XOR,我可以在恒定时间内计算X + 1和Y的XOR吗?
有些人指出,可以使用AND和NOT在恒定时间内计算XOR。 我如何为AND做同样的事情? 我如何计算从0到(n)^ {1/2} - 1的数字和从0到(n)^ {1/2} - 1的每个数字的数字。 我希望在O(n)时间内完成此操作,并且无法使用XOR,OR和AND操作。
P.S。 - 这里假设RAM模型,并且<操作(加,乘,除)< log(n)位数可以是恒定时间。
答案 0 :(得分:2)
您可以从NAND构建XOR门(图here),因此您可以使用if
(NOT)和!
AND &&
语句来执行此操作如果我们在这里使用C / C ++ / PHP作为例子)。至于在恒定时间内进行计算,每次迭代的计算都是相同的,因此它将是常数。
答案 1 :(得分:2)
可以使用AND和NOT构建XOR(并将它们组合以构建NAND)。你能使用AND而不是吗?
在C#中:
Func<bool, bool, bool> nand = (p, q) => !(p && q);
Func<bool, bool, bool> xor = (p, q) =>
{
var s1 = nand(p, q);
var s2a = nand(p, s1);
var s2b = nand(q, s1);
return nand(s2a, s2b);
};
我模仿这个:http://en.wikipedia.org/wiki/NAND_logic#XOR
在C#中,使用模数,求和和乘法。 (限制:我使用uint,所以最多32位。它适用于ulong,所以最多64位)
uint a = 16;
uint b = 5;
uint mult = 1;
uint res = 0;
for (int i = 0; i < 32; i++)
{
uint i1 = a % 2;
uint i2 = b % 2;
if (i1 != i2) {
res += mult;
}
a /= 2;
b /= 2;
mult *= 2;
}
res是响应。
模数可以建立在除法,乘法和减法之上。
答案 2 :(得分:2)
是
从[1x1]网格开始:
H(-1) = [ 0 ]
然后应用递归:
H(i) = [ H(i-1) H(i-1)+(1 << i)
H(i-1)+(1 << i) H(i-1) ]
其中表示矩阵连接。即每次递归使每个维度中网格的大小加倍。重复,直到达到所需的大小。
答案 3 :(得分:1)
如果两者不相等,那么它们就是xor。
xorBits(bit1,bit2){
return bit1 != bit2?1:0
}
xorBooleans(boolean1,boolean2){
return boolean1 != boolean2
}
答案 4 :(得分:0)
首先,令k为2的最小幂,大于或等于sqrt(n)。 k仍然是O(sqrt(n))所以这不会改变复杂性。
为了构造完整的k by k表,我们一次构造一行。
我们从第0行开始:这很容易,因为0 x或j = j。
for i in xrange(k):
result[0][i] = i
接下来,我们以灰色代码顺序查看行。格雷码是一种通过一次改变一位来计数从0到1的每个数字的方法,而不是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中的位数),但是这没关系,因为我们没有在main函数的内部循环中使用它。