剑指Offer18--面试题56 - I. 数组中数字出现的次数
题目描述
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
限制:
2 <= nums <= 10000
方法一:hashSet (但是题目要求空间O(1))
代码:
class Solution {
public int[] singleNumbers(int[] nums) {
Set<Integer> set = new HashSet<>();
for(int num:nums){
if(set.contains(num)){
set.remove(num);
}else{
set.add(num);
}
}
//将集合转换为int数组
return set.stream().mapToInt(Integer::intValue).toArray();
}
}
异或(位运算)
分析:
这题用异或来解有些难理解
此处解释比较详细
自己的理解+当自己的笔记用,可能有错:
首先要明白异或的性质:
交换律:A ^ B = B ^ A;
结合律:A ^ (B ^ C) = (A ^ B) ^ C;
恒等律:X ^ 0 = X;
归零律:X ^ X = 0;
自反:A ^ B ^ B = A ^ 0 = A;
对于任意的 X: X ^ (-1) = ~X;
如果 A ^ B = C 成立,那么 A ^ B = C,B ^ C = A;
代码:
class Solution {
public int[] singleNumbers(int[] nums) {
int xorNumber = nums[0];
for(int k=1; k<nums.length; k++){
xorNumber ^=nums[k];
}
int onePosition = xorNumber&(-xorNumber);
int ans1 = 0, ans2 = 0;
for(int i=0; i<nums.length; i++){
if((nums[i]&onePosition)==onePosition){
ans1^=nums[i];
}else{
ans2^=nums[i];
}
}
return new int[] {ans1^0, ans2^0};
}
}