文章目录
题目难度:中等
(1)题目描述
一个整型数组
nums
里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例1:
输入:nums = [4, 1, 4, 6]
输出:[1, 6] 或 [6, 1]
示例2:
输入:nums = [1, 2, 3, 4, 5, 6, 1, 2, 3, 4]
输出:[5, 6] 或 [6, 5]
LeetCode链接:剑指 Offer 56 - I. 数组中数字出现的次数
(2)解题思路:分组异或
- 先来思考一下这个问题
一个整型数组里出现一次的数只有一个,其他数字都出现了两次,请找出这个只出现一次的数字。
要解决这个问题,利用异或的特性(两数相同异或等于0,0和一个数异或就等于其本身),所以数组中只有一个出现一次的数,那么只需要异或整个数组就可以得到这个只出现一次的数。
- 回到本题,出现一次的数有两个
假设输入:nums = [1, 2, 3, 4, 5, 6, 1, 2, 3, 4],我们需要从中找到 5 和 6
类比前面问题的解法,异或整个数组,得到的是 5 和 6 的异或结果,显然是不行。
那么我们能不能把要找的这两个数字,分成两组,一组放一个,这样分别异或这两组数,就得到了这两个数字。
- 分组的要求
1)两个只出现一次的数必须在不同组
2)两个相同的数必须出现在同一组
比如分为(1 3 1 3 5)和(2 4 2 4 6),这样就很容易找到这两个数字了。
- 如何分组呢?(问题核心)
异或整个数组的结果就是这两个出现一次的数异或的结果,是一定不等于 0 的,那么说明这个异或结果的二进制序列中一定是有 1 的,找到这个 1,我们就可以利用这个来分组
nums = [1, 2, 3, 4, 5, 6, 1, 2, 3, 4],全部异或的结果就是 5 和 6 异或的结果,即 0101 和 0110 异或的结果 0011
0011 中为1 的二进制位表示什么意思呢,分析不难知道,异或相同为 0 ,相异为 1,所以二进制位是 1,就表示 5 和 6 的二进制数在第一、二位上的数是不同的。这就是分组依据。
我们就以第一个为 1 二进制位为分组条件,将数组中第一个二进制位为 1 的数分为一组,第二个二进制位为 0 的数分为另一组,这样就把 5 和 6 成功分到不同的组,而剩下的那些相同的数(1 和 1、2 和 2,3 和 3、4 和 4),因为数值相同,所以它们的第一个二进制位一定是相同的。这样就同时把两个相同的数划分到同一组了。
- 为了能够更清晰的看到分组情况,我画了一个表格:
数组 | 二进制序列 | 第一个二进制位 |
---|---|---|
1 | 0001 | 1 |
1 | 0001 | 1 |
2 | 0010 | 0 |
2 | 0010 | 0 |
3 |