已知Python异或生成的列表z,如何推导原输入列表e?
嘿,这个问题挺有意思的——咱们一步步拆解,从数学逻辑到代码实现都讲明白!
首先明确背景:原始列表 e 通过规则 z[i] = e[i] ^ e[(i+1) % len(e)] 生成了结果列表 z,现在已知 z,要反推回 e。
第一步:先搞懂核心数学关系
假设列表长度为 n,把每个位置的异或关系列出来:
z[0] = e[0] ^ e[1]z[1] = e[1] ^ e[2]z[2] = e[2] ^ e[3]- ...
z[n-1] = e[n-1] ^ e[0]
关键:先判断是否有解
把所有等式的左右两边分别做异或运算:
左边是 z[0] ^ z[1] ^ ... ^ z[n-1]
右边是 (e[0]^e[1]) ^ (e[1]^e[2]) ^ ... ^ (e[n-1]^e[0])
根据异或的核心性质:a ^ a = 0、a ^ 0 = a,右边每个 e 元素都出现了两次,所以最终结果是 0。这意味着只有当所有 z 元素的异或和为 0 时,才有解——否则不存在这样的原始列表 e。
第二步:推导原始列表的表达式
假设满足有解的前提,接下来我们可以用一个自由变量(比如 e[0])推导出所有其他元素:
- 从第一个式子可得:
e[1] = e[0] ^ z[0] - 代入第二个式子:
e[2] = e[1] ^ z[1] = e[0] ^ z[0] ^ z[1] - 以此类推,第
i个元素(i ≥ 1)的表达式是:e[i] = e[0] ^ (z[0] ^ z[1] ^ ... ^ z[i-1])
最后验证一下最后一个元素:因为 z[0]^...^z[n-1] = 0,所以 z[n-1] = z[0]^...^z[n-2],而 e[n-1] = e[0] ^ (z[0]^...^z[n-2]),所以 e[n-1]^e[0] = z[n-1],完全符合原始规则,没问题。
第三步:代码实现
因为 e[0] 是自由变量,所以解不是唯一的——你可以指定任意 e[0] 的值,得到对应的原始列表。下面是两种实现方式:
方式1:获取以 e[0]=0 为基础的解
def recover_e(z): n = len(z) # 先检查是否有解 xor_total = 0 for num in z: xor_total ^= num if xor_total != 0: return None # 无解 e = [0] * n current_prefix_xor = 0 for i in range(1, n): current_prefix_xor ^= z[i-1] e[i] = e[0] ^ current_prefix_xor # 可选验证:确保最后一个元素符合规则 assert (e[-1] ^ e[0]) == z[-1] return e
方式2:指定任意 e[0] 来恢复列表
如果你想得到特定开头的原始列表(比如题目里的 e[0]=97),可以用这个版本:
def recover_e_with_start(z, e0): n = len(z) xor_total = 0 for num in z: xor_total ^= num if xor_total != 0: return None # 无解 e = [e0] * n current_prefix_xor = 0 for i in range(1, n): current_prefix_xor ^= z[i-1] e[i] = e0 ^ current_prefix_xor assert (e[-1] ^ e0) == z[-1] return e
测试一下
用题目里的例子来验证:
题目中 e = [97,71,86,115,98,71,56,61],对应的 z 计算后是 [42, 121, 43, 27, 31, 127, 11, 36]。我们用这个 z 来恢复:
test_z = [42, 121, 43, 27, 31, 127, 11, 36] # 恢复题目里的原始列表 original_e = recover_e_with_start(test_z, 97) print("恢复的原始列表:", original_e) # 输出:[97, 71, 86, 115, 98, 71, 56, 61],和题目一致!
总结
- 先检查
z的异或总和是否为0,不为0则无解; - 解不唯一,取决于你选择的
e[0]值; - 通过累积异或
z的前缀,就能推导出所有其他元素。
内容的提问来源于stack exchange,提问作者Rusher

