力扣389.找不同

题目

给定两个字符串 s 和 t ,它们只包含小写字母。

字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。

请找出在 t 中被添加的字母。

 

示例 1:

输入:s = "abcd", t = "abcde"
输出:"e"
解释:'e' 是那个被添加的字母。

示例 2:

输入:s = "", t = "y"
输出:"y"

提示:

  • 0 <= s.length <= 1000
  • t.length == s.length + 1
  • s 和 t 只包含小写字母

 详解

此题目涉及到一个非常基础且重要的知识点:异或,下面我将先带大家复习异或的性质,再对题目以及代码做出最详细的解释

异或运算(XOR,全称为“exclusive OR”)是一种二进制运算,它接受两个操作数,返回一个结果。异或运算的特性是,如果两个相应的二进制位相同,则结果为 0;如果不同,则结果为 1。异或运算在计算机科学和数字电子中有着广泛的应用。

异或

异或运算的真值表

对于两个二进制位 ( A ) 和 ( B ),异或运算的结果 ( A \oplus B ) 可以表示如下:

( A )( B )( A \oplus B )
000
011
101
110

异或运算的性质

  1. 交换律:( A \oplus B = B \oplus A )
  2. 结合律:( (A \oplus B) \oplus C = A \oplus (B \oplus C) )
  3. 自逆性:( A \oplus A = 0 )
  4. 单位元:( A \oplus 0 = A )
  5. 分配律:( A \oplus (B \land C) = (A \oplus B) \land (A \oplus C) )

异或运算的应用

  1. 数据加密:异或运算常用于简单的加密算法,如一次一密(OTP)。
  2. 错误检测和校正:在通信和存储中,异或运算用于奇偶校验位的计算。
  3. 数字逻辑设计:在数字电路中,异或门是基本的逻辑门之一。
  4. 计算机图形学:用于位图图像的处理,如图像的翻转和透明度计算。
  5. 算法设计:在一些算法中,异或运算用于高效地交换两个变量的值,而不需要额外的存储空间。

示例

假设我们有两个二进制数 ( 0110 ) 和 ( 1100 ),进行异或运算的过程如下:

  0110
⊕ 1100
------
  1010

逐位进行异或运算,得到结果 ( 1010 )。

在编程中的应用

在编程中,异或运算通常用符号 ^ 表示。例如,在 C、C++、Java 和 Python 中,^ 运算符用于执行异或运算。

int a = 6;  // 二进制表示为 0110
int b = 12; // 二进制表示为 1100
int result = a ^ b; // 结果为 10 (二进制 1010)

解题思路

题目中有两个显而易见的要点:

i.两个字符串只包含小写字母;

ii.字符串t是随机重排;

思路一:for循环去遍历这两个字符串,可是由于随机重排,导致每个s字符串的元素都要遍历一遍t字符串,这样运行下去时间复杂度太高了,太麻烦了。

思路二:对两个字符串根据ascii码进行冒泡排序,再一一对比,也很麻烦。

下面用刚刚学习的异或操作来处理,附带代码详细执行逻辑

思路

  1. 异或运算的性质

    • 异或运算(XOR)有一个重要的性质:对于任意两个相同的数 a,有 a XOR a = 0
    • 另一个性质是:对于任意数 a,有 a XOR 0 = a
    • 这些性质使得异或运算非常适合用于查找不同的元素。
  2. 算法流程

    • 初始化一个字符 c 为 0。
    • 遍历字符串 s 的每一个字符,同时对应地获取字符串 t 中的字符。
    • 对这些字符进行异或运算,将结果累积在 c 中。
    • 最后,再对 t 中多出的一个字符进行异或运算。
    • 返回最终的字符 c,它就是 t 中比 s 多出的那个字符。

代码解释

public class Solution {
    public char findTheDifference(String s, String t) {
        // 初始化字符 c 为 0
        char c = 0;
        
        // 遍历字符串 s 的每一个字符
        for (int i = 0; i < s.length(); ++i) {
            // 对 s 中的字符进行异或运算
            c ^= s.charAt(i);
            // 对 t 中的对应字符进行异或运算
            c ^= t.charAt(i);
        }
        
        // 对 t 中多出的一个字符进行异或运算
        c ^= t.charAt(s.length());
        
        // 返回多出的字符
        return c;
    }
}

收起

  • 初始化char c = 0; 初始化一个字符 c 为 0,用于存储最终的结果。
  • 遍历字符串for (int i = 0; i < s.length(); ++i) 遍历字符串 s 的每一个字符。
  • 异或运算
    • c ^= s.charAt(i); 对 s 中的字符进行异或运算。
    • c ^= t.charAt(i); 对 t 中的对应字符进行异或运算。
  • 处理多出的字符c ^= t.charAt(s.length()); 对 t 中多出的一个字符进行异或运算。
  • 返回结果return c; 返回最终的字符 c

为什么有效

由于 s 和 t 只相差一个字符,且 t 是由 s 添加一个字符后打乱顺序得到的,因此通过异或运算可以有效地找出这个多出的字符。所有相同的字符在异或运算后都会抵消为 0,最终的结果就是那个多出的字符。

代码详细执行过程

详细分析一下当 s 是 "asdf" 而 t 是 "dsafg" 时,异或运算的过程。

输入

  • s = "asdf"
  • t = "dsafg"

目标

找出 t 中比 s 多出的字符。

步骤

  1. 初始化

    • char c = 0; 初始化字符 c 为 0。
  2. 遍历字符串

    • 使用 for 循环遍历 s 的每一个字符,同时对 t 中的对应字符进行异或运算。
  3. 异或运算

    • c ^= s.charAt(i); 对 s 中的字符进行异或运算。
    • c ^= t.charAt(i); 对 t 中的对应字符进行异或运算。
  4. 处理多出的字符

    • c ^= t.charAt(s.length()); 对 t 中多出的一个字符进行异或运算。
  5. 返回结果

    • return c; 返回最终的字符 c

详细过程

假设我们用 ASCII 码表示字符进行运算(因为 char 在 Java 中是 16 位的 Unicode 字符,但为了简化说明,我们用 ASCII 码表示):

  • 'a' 的 ASCII 码是 97
  • 's' 的 ASCII 码是 115
  • 'd' 的 ASCII 码是 100
  • 'f' 的 ASCII 码是 102

循环过程(小写字母转ASCII码再转二进制进行异或)

  1. i = 0

    • c ^= s.charAt(0); → c = 0 XOR 97 → c = 97
    • c ^= t.charAt(0); → c = 97(01100001) XOR 100 (01100100)→ c = 5(00000101)
  2. i = 1

    • c ^= s.charAt(1); → c = 5(00000101) XOR 115 (01110011)→ c = 118(01110110)
    • c ^= t.charAt(1); → c = 118(01110110) XOR 115(01110011) → c = 5(00000101)
  3. i = 2

    • c ^= s.charAt(2); → c = 5(00000101) XOR 100 (01100100)→ c = 97(01100001)
    • c ^= t.charAt(2); → c = 97 XOR 97 → c = 0
  4. i = 3

    • c ^= s.charAt(3); → c = 0 XOR 102 → c = 102
    • c ^= t.charAt(3); → c = 102 XOR 102 → c = 0

处理多出的字符

  • c ^= t.charAt(s.length()); → c = 0 XOR 103 → c = 103,其中 103 是 'g' 的 ASCII 码。

最终结果

  • return c; 返回字符 c,即 'g'

总结

通过上述过程,我们可以看到,尽管 t 是通过对 s 进行重排得到的,但由于 t 中多出一个字符 'g',在异或运算的过程中,所有相同的字符都会被抵消,最终的结果就是多出的字符 'g'

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值