剑指 Offer 56 - I. 数组中数字出现的次数(位运算)-真是妙蛙种子吃着妙脆角秒进米奇妙妙屋秒到家了
一、题目
剑指 Offer 56 - I. 数组中数字出现的次数(位运算的妙用)
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例1:
1 | 输入: [4,1,4,6] |
示例2:
1 | 输入: [1,2,10,4,1,4,3,3] |
二、分析
1.方法1:排序后,暴力遍历
这种方法思路简单,但是时间复杂度较高。排序消耗O(nlogn),遍历消耗O(n),思路简单,但是不是最优解。
2.方法2:位运算
分析
- 我们知道异或运算有个特点,0和任何数异或是任何数本身,先记住这个结论。我们先将此题简化为一个整型数组中只有一个数字$x$只出现了一次,其他数字$a_i$ 都出现了两次。数组定义如下$nums=[ a_i, a_i ,x]$对于这个简化了的题,我们如果想到用位运算异或的性质,就很好求解了,直接将数组中所有的数值做异或运算,结果就是出现了一次的数$x$。公式如下:
$$
x=a_i\quad xor\quad a_i\quad xor\quad x
$$
而这道题里面有两个数字$x,y$出现了一次。$nums=[ a_i ,a_i, x, y]$我们将其分隔为两部分$nums1,nums2$(如何分隔下面会细说),保证x,y分别在不同的部分中。然后转换为1.中将两部分用异或位运算就可以得到$x,y$。公式如下:
$$
x=a_i\quad xor\quad a_i\quad xor\quad x\
y=a_k\quad xor\quad a_k\quad xor\quad y
$$3.如何将$nums$ 分成$nums1和nums2$,同时还得保证$x\in nums1$ $y\in nums2$。我们知道x和y一定不相同,假设其二进制第n位不同,两者异或的结果在第n为一定为1。我们只需要找到改位置。然后拿$1<<n $ 去和$x,y$做与运算,根据结果0,1来将其分成两组。(两个运算结果一定一个为1,一个为0)
$$
1<<n\quad & \quad x\
1<<n\quad & \quad y
$$
至于其他存在两个重复的数分组也是用这种方法,只要保证相同的数分在同一组就行。$比如a1,a1在一组。a2,a2在一组$。
复杂度
- 时间:O(n):遍历 nums使用 O(n)时间,x⊕y 二进制位使用 O(32) = O(1)时间。
- 空间:O(1)
三、代码
1.方法1:排序后,暴力遍历
1 | ''' |
2.方法2:位运算
1 | ''' |
四、总结
这道题用位运算真是妙蛙种子吃着妙脆角秒进米奇妙妙屋秒到家了。
位运算常见性质总结:
1 | 0 or 任何数等于其本身 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 坚韧的长线「串联」散落的珍珠!
评论



