← 返回题目列表

找不同字符为什么可以用异或?异或如何抵消成对字符?

简单 第 18 / 26 题 更新于 2026/08/01
位运算异或字符串抵消

简化版

两个字符串 st 中,ts 多一个字符。把两个字符串所有字符都异或起来,成对出现的字符会抵消成 0,最后剩下的就是多出来的字符。

详细版

异或满足 x ^ x = 0x ^ 0 = x,并且交换律、结合律成立。因此字符顺序不重要,只要相同字符出现两次就会抵消。遍历 st 的所有字符,用一个变量 ans 累积异或,最后把结果转回字符。

时间复杂度 O(n),空间复杂度 O(1)。这题也可以用计数数组,但异或写法更简洁,适合“只有一个额外元素”的模型。

完整版教学

一、题目结构为什么适合异或

ts 打乱后额外加了一个字符。也就是说,除了多出来的那个字符,其他字符都能成对匹配。

s = "abcd"
t = "abcde"

把所有字符放到一起,a,b,c,d 都出现两次,只有 e 出现一次。

二、异或的抵消性质

异或有三条关键性质:

x ^ x = 0
x ^ 0 = x
x ^ y = y ^ x

这意味着相同元素无论隔多远,都能在整体异或里抵消。

表达式结果
a ^ a0
a ^ b ^ ab
a ^ b ^ b ^ c ^ ac

记忆钩子:异或适合“成双抵消,剩一个”的题。

三、为什么字符也能异或

字符在计算机里有编码值,比如小写字母可以看作整数。Java 中 char 可以参与位运算,会按编码值计算。

'a' ^ 'a' = 0

所以对字符异或,本质是在对它们的编码整数异或。最后把整数结果转回 char

四、代码模板

char findTheDifference(String s, String t) {
    int ans = 0;
    for (char c : s.toCharArray()) ans ^= c;
    for (char c : t.toCharArray()) ans ^= c;
    return (char) ans;
}

也可以把两个循环合并,但分开写更清楚。

五、用例子推演

s="abc"t="bcae"

ans = a ^ b ^ c ^ b ^ c ^ a ^ e
    = (a^a) ^ (b^b) ^ (c^c) ^ e
    = e

因为异或满足交换律和结合律,字符顺序被打乱不影响结果。

六、和计数数组的对比

计数数组也能做:统计 t,减去 s,剩下计数为 1 的字符就是答案。

方法空间特点
异或O(1)简洁,适合单个额外字符
计数O(字符集)更通用,可处理多个差异

如果题目变成多出多个字符,异或就不够了,需要计数或哈希。

七、常见误区与追问

  • 误区:认为异或只能用于数字。 字符也有编码值,可以参与位运算。
  • 误区:担心字符串顺序不同。 异或满足交换律,顺序不影响抵消。
  • 误区:多出多个字符也用同样方法。 多个剩余字符异或会混在一起,无法直接还原。
  • 追问:为什么 x^x=0 每一位相同异或都为 0。
  • 追问:和求和相减有什么区别? 求和也能做,但异或不担心加和溢出且语义更贴合抵消。
  • 追问:空间复杂度是多少? 只用一个累积变量,是 O(1)

八、加强记忆

找不同字符就是“多一个,其他都成双”。异或的天赋正是成双抵消:x^x=0,剩下谁,答案就是谁。只要题目保证只多一个元素,且元素可编码成整数,异或就是最短路径;一旦多出多个,就换计数。