添加到 FatalError 的好答案,该行return f(b)^f(a-1);
可以更好地解释。简而言之,这是因为 XOR 具有这些奇妙的特性:
- 它是关联的- 将括号放在任何你想要的地方
- 它是可交换的- 这意味着您可以移动操作员(他们可以“通勤”)
这两者都在行动:
(a ^ b ^ c) ^ (d ^ e ^ f) = (f ^ e) ^ (d ^ a ^ b) ^ c
像这样:
a ^ b = c
c ^ a = b
加法和乘法是其他关联/交换运算符的两个示例,但它们不会自行反转。好的,那么,为什么这些属性很重要?嗯,一个简单的方法是将它扩展成真正的样子,然后你就可以看到这些属性在起作用。
首先,让我们定义我们想要的并将其命名为 n:
n = (a ^ a+1 ^ a+2 .. ^ b)
如果有帮助,请将 XOR (^) 视为加法。
让我们也定义函数:
f(b) = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b
b
大于a
,因此只需安全地放入几个额外的括号(我们可以这样做,因为它是关联的),我们也可以这样说:
f(b) = ( 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ (a-1) ) ^ (a ^ a+1 ^ a+2 .. ^ b)
这简化为:
f(b) = f(a-1) ^ (a ^ a+1 ^ a+2 .. ^ b)
f(b) = f(a-1) ^ n
接下来,我们使用反转属性和交换性来给我们一条神奇的线:
n = f(b) ^ f(a-1)
如果您一直将 XOR 视为加法,那么您将在那里进行减法。XOR 是 XOR 加是减!
我自己怎么想出这个?
记住逻辑运算符的属性。如果有帮助的话,几乎可以像加法或乘法一样使用它们。and (&)、xor (^) 和 or (|) 是关联的,这感觉很不寻常,但它们是!
首先运行简单的实现,在输出中查找模式,然后开始查找确认模式为真的规则。进一步简化您的实施并重复。这可能是最初创建者采用的路线,突出显示它不是完全最优的事实(即使用 switch 语句而不是数组)。