题目描述
给定一个整数数组 nums
,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。
示例 :
输入: [1,2,1,3,2,5]
输出: [3,5]
注意:
- 结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。
- 你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-number-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
注: 异或的性质可参考136. 只出现一次的数字
首先,将所有数字异或,得到一个结果,这个结果等价于只出现一次的两个数字之间异或。因为异或存在交换律、结合律,以及两个相同数字异或为0,0与任何一个数字异或为该数字,所以其他出现两次的数字,两两异或都为0,最后就只剩下一堆0和两个只出现一次的数字之间异或。
观察得到的异或结果,可以发现:结果为1的位就是2个数字不同的位。找出异或结果不同的位,比如,最低非0位,记为第i
位。设置两个变量num1
和num2
,分别初始化为0。再次遍历数组,如果数字的第i
位为0,让该数字和num1
异或;否则,与num2
异或。其他数字不会对最终的结果造成影响,因为其他每一位出现1或0的次数都是2的倍数。
程序(Java)
class Solution {
public int[] singleNumber(int[] nums) {
int allXOR = 0;
for(int num: nums) // 计算全部异或结果
allXOR ^= num;
// 寻找非0最低位
int bit_1 = 1;
while((allXOR & 1) == 0){
allXOR >>= 1;
bit_1 <<= 1;
}
// 还可以这样写:int bit_1 = allXOR & (-allXOR);
int num1 = 0;
int num2 = 0;
for(int num: nums){
if((num & bit_1) == 0) // 位为 0
num1 ^= num;
else
num2 ^= num;
}
return new int[]{num1, num2};
}
}