LeetCode 389 找不同
文章目录
- 摘要
- 描述
- 题解答案
- 题解代码分析
- 代码拆解
- 示例测试及结果
- 时间复杂度
- 空间复杂度
- 总结
摘要
在日常开发中,经常会遇到“数据校验”或者“缺失元素查找”的场景,比如比对两个列表,确认是否有新增/丢失的条目。LeetCode 389 的问题就很像这个场景:我们有两个字符串,其中一个是另一个的乱序版本,只不过多了一个字母。我们需要快速找到那个被“偷偷加进去”的字母。
描述
题目很直接:给定两个字符串 s
和 t
,它们只包含小写字母,并且满足 t
是由 s
随机重排后再添加一个字母得到的。
要求:找出 t
中多出来的那个字母。
举几个例子:
-
示例 1
输入: s = "abcd", t = "abcde" 输出: "e" 解释: "e" 就是新加进去的字母。
-
示例 2
输入: s = "", t = "y" 输出: "y" 解释: 因为 s 是空的,所以 t 的字母就是新增的。
题解答案
这道题有几种常见的解法:
- 计数数组:用一个大小为 26 的数组记录字母频率,最后多出来的那个就是答案。
- ASCII 值求和:计算
t
的字符 ASCII 总和减去s
的 ASCII 总和,结果就是新增的字母。 - 异或运算(最优雅):把
s
和t
的所有字母进行异或,成对的字母会被抵消,最后剩下的就是新增的字母。
我更推荐用 异或,因为它不仅写起来简洁,而且只需要一次遍历,空间复杂度也非常低。
题解代码分析
我们直接看 Swift 的代码实现:
import Foundationclass Solution {func findTheDifference(_ s: String, _ t: String) -> Character {var xorValue = 0// 遍历 s 和 t,把每个字符的 ASCII 值进行异或for char in s {xorValue ^= Int(char.asciiValue!)}for char in t {xorValue ^= Int(char.asciiValue!)}// 剩下的就是那个唯一不同的字符return Character(UnicodeScalar(xorValue)!)}
}
代码拆解
- 初始化
xorValue
:存储所有字符异或后的结果。 - 遍历字符串 s:每个字符转成 ASCII 值,再和
xorValue
做异或。 - 遍历字符串 t:同样操作,成对的字符会被抵消(因为
a ^ a = 0
)。 - 剩下的结果:就是新增的那个字母对应的 ASCII 值。
- 转回 Character:用
UnicodeScalar
转换后返回。
这种方法特别优雅,因为完全符合“两个集合的差异”这个直觉。
示例测试及结果
我们来跑几个例子:
let solution = Solution()print(solution.findTheDifference("abcd", "abcde"))
// 输出: eprint(solution.findTheDifference("", "y"))
// 输出: yprint(solution.findTheDifference("aabb", "ababc"))
// 输出: c
结果完全符合预期。
时间复杂度
- 我们遍历了
s
和t
各一次,所以整体是 O(n),其中n
是字符串的长度。
空间复杂度
- 我们只用了一个整数
xorValue
来存储异或结果,所以是 O(1)。
总结
这道题虽然描述很简单,但其实是位运算的经典应用。
- 如果用计数数组,也能解出来,但代码稍显繁琐;
- 如果用 ASCII 求和,也行,但不如异或直观;
- 最优雅的就是异或:不仅写得简洁,而且效率高。
在实际开发里,异或法也经常用在校验或者差异检测场景,比如网络通信的校验位计算,或者文件比对。
所以,别小看这道题,它其实帮我们复习了一个非常实用的技巧。