在这里插入图片描述
在这里插入图片描述

摘要

在日常开发中,经常会遇到“数据校验”或者“缺失元素查找”的场景,比如比对两个列表,确认是否有新增/丢失的条目。LeetCode 389 的问题就很像这个场景:我们有两个字符串,其中一个是另一个的乱序版本,只不过多了一个字母。我们需要快速找到那个被“偷偷加进去”的字母。

描述

题目很直接:给定两个字符串 st,它们只包含小写字母,并且满足 t 是由 s 随机重排后再添加一个字母得到的。

要求:找出 t 中多出来的那个字母。

举几个例子:

  • 示例 1

    输入: s = "abcd", t = "abcde"
    输出: "e"
    解释: "e" 就是新加进去的字母。
    
  • 示例 2

    输入: s = "", t = "y"
    输出: "y"
    解释: 因为 s 是空的,所以 t 的字母就是新增的。
    

题解答案

这道题有几种常见的解法:

  1. 计数数组:用一个大小为 26 的数组记录字母频率,最后多出来的那个就是答案。
  2. ASCII 值求和:计算 t 的字符 ASCII 总和减去 s 的 ASCII 总和,结果就是新增的字母。
  3. 异或运算(最优雅):把 st 的所有字母进行异或,成对的字母会被抵消,最后剩下的就是新增的字母。

我更推荐用 异或,因为它不仅写起来简洁,而且只需要一次遍历,空间复杂度也非常低。

题解代码分析

我们直接看 Swift 的代码实现:

import Foundation

class 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)!)
    }
}

代码拆解

  1. 初始化 xorValue:存储所有字符异或后的结果。
  2. 遍历字符串 s:每个字符转成 ASCII 值,再和 xorValue 做异或。
  3. 遍历字符串 t:同样操作,成对的字符会被抵消(因为 a ^ a = 0)。
  4. 剩下的结果:就是新增的那个字母对应的 ASCII 值。
  5. 转回 Character:用 UnicodeScalar 转换后返回。

这种方法特别优雅,因为完全符合“两个集合的差异”这个直觉。

示例测试及结果

我们来跑几个例子:

let solution = Solution()

print(solution.findTheDifference("abcd", "abcde")) 
// 输出: e

print(solution.findTheDifference("", "y")) 
// 输出: y

print(solution.findTheDifference("aabb", "ababc")) 
// 输出: c

结果完全符合预期。

时间复杂度

  • 我们遍历了 st 各一次,所以整体是 O(n),其中 n 是字符串的长度。

空间复杂度

  • 我们只用了一个整数 xorValue 来存储异或结果,所以是 O(1)

总结

这道题虽然描述很简单,但其实是位运算的经典应用。

  • 如果用计数数组,也能解出来,但代码稍显繁琐;
  • 如果用 ASCII 求和,也行,但不如异或直观;
  • 最优雅的就是异或:不仅写得简洁,而且效率高。

在实际开发里,异或法也经常用在校验或者差异检测场景,比如网络通信的校验位计算,或者文件比对。

所以,别小看这道题,它其实帮我们复习了一个非常实用的技巧。

Logo

加入「COC·上海城市开发者社区」,成就更好的自己!

更多推荐