欢迎访问原文所在博客:https://52heartz.top/articles/leetcode-136-single-number/
解答1[Java]:
class Solution {
public int singleNumber(int[] nums) {
}
}
思路
- If we take XOR of zero and some bit, it will return that bit
- a ⊕ 0 = a a \oplus 0 = a a⊕0=a
- If we take XOR of two same bits, it will return 0
- a ⊕ a = 0 a \oplus a = 0 a⊕a=0
- a ⊕ b ⊕ a = ( a ⊕ a ) ⊕ b = 0 ⊕ b = b a \oplus b \oplus a = (a \oplus a) \oplus b = 0 \oplus b = b a⊕b⊕a=(a⊕a)⊕b=0⊕b=b
So we can XOR all bits together to find the unique number.
本题拓展
有一个 n 个元素的数组,除了两个数只出现一次外,其余元素都出现两次,让你找出这两个只出现一次的数分别是几,要求时间复杂度为 O(n) 且再开辟的内存空间固定(与 n 无关)。
示例 :
输入: [1,2,2,1,3,4]
输出: [3,4]题目再解析
根据前面找一个不同数的思路算法,在这里把所有元素都异或,那么得到的结果就是那两个只出现一次的元素异或的结果。
然后,因为这两个只出现一次的元素一定是不相同的,所以这两个元素的二进制形式肯定至少有某一位是不同的,即一个为 0 ,另一个为 1 ,现在需要找到这一位。
根据异或的性质
任何一个数字异或它自己都等于 0
,得到这个数字二进制形式中任意一个为 1 的位都是我们要找的那一位。再然后,以这一位是 1 还是 0 为标准,将数组的 n 个元素分成两部分。
- 将这一位为 0 的所有元素做异或,得出的数就是只出现一次的数中的一个
- 将这一位为 1 的所有元素做异或,得出的数就是只出现一次的数中的另一个。
这样就解出题目。忽略寻找不同位的过程,总共遍历数组两次,时间复杂度为O(n)。
核心思想
两个数不一样,肯定至少有一个二进制位是不一样的。我们就从不一样的二进制位中选择一个。设这两个数为A 和 B。
现在假设我们已经选择了某一个二进制位,假设我们选择的是从右向左数第2位,简称第2位。
因为除了这两个数之外其他的数都是成对出现的,所以其他的数中,第2位是0的数是成对出现的,第2位是1的数也是成对出现的。
而A和B的第2位,只有两种可能:
(1)A的第2位是1,B的第2位是0;
(2)A的第2位是0,B的第2位是1。
所以,如果我们把第2位为0的所有数都相互之间做异或运算,必然能够找出A和B中的一个数字,因为其他的数都是成对出现的,异或之后所有位都0了。
再把第2位为1的所有数都相互之间做异或运算,必然能够找出A和B中的另外一个数字。