❓剑指 Offer 56 - I. 数组中数字出现的次数
难度:中等
一个整型数组 nums
里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是
O
(
n
)
O(n)
O(n),空间复杂度是
O
(
1
)
O(1)
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.length <= 10000
💡思路:位运算
基础知识必知:一篇文章搞懂位运算!!!
两个相等的元素 异或 的结果为 0,而 0 与任意数 x
异或 的结果都为 x
。
对本题给的数组的所有元素执行异或操作,得到的是两个不存在重复的元素异或的结果。例如对于数组 [x,x,y,y,z,k]
,x^x^y^y^z^k = 0^y^y^z^k = y^y^z^k = 0^z^k = z^k
。
两个不相等的元素在位级表示上一定会有所不同,因此这两个元素异或得到的结果 diff
一定不为 0:
- 使用
ans[0] = diff
先保存这两个数的结果; - 位运算
diff
&
-diff
能得到diff
位级表示中 最右侧为 1 的位,令diff = diff & -diff
。 - 将
diff
作为区分两个元素的依据,一定有一个元素对diff
进行 与 运算的结果为diff
,另一个结果为 0。
设不相等的两个元素分别为 x
和 y
,遍历数组所有元素,判断每一个元素与 diff
的 与 结果是否为 diff
:
- 如果是的话将元素与
x
进行 异或 并赋值给ans[1]
; - 数组中相等的元素一定会同时与
x
异或操作,而且这些相等的元素异或的结果为 0,因此最后 只剩下x
与 0 异或的结果; - 另一个元素
y = ans[0] ^ x
。
🍁代码:(C++、Java)
C++
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
vector<int> ans(2);
int diff = 0;
for(int num : nums){//得到只出现一次的两个数的异或
diff ^= num;
}
ans[0] = diff; //记录两个数的异或结果
diff &= -diff; //得到最后一位1
for(int num : nums){//得到其中一个数
if((num & diff) == diff){
ans[1] ^= num;
}
}
ans[0] ^= ans[1];//得到另一个数
return ans;
}
};
Java
class Solution {
public int[] singleNumbers(int[] nums) {
int[] ans = new int[2];
int diff = 0;
for(int num : nums){//得到只出现一次的两个数的异或
diff ^= num;
}
ans[0] = diff; //记录两个数的异或结果
diff &= -diff; //得到最后一位1
for(int num : nums){//得到其中一个数
if((num & diff) == diff){
ans[1] ^= num;
}
}
ans[0] ^= ans[1];//得到另一个数
return ans;
}
}
🚀 运行结果:
🕔 复杂度分析:
- 时间复杂度: O ( n ) O(n) O(n),我们只需要遍历数组两次。
- 空间复杂度: O ( 1 ) O(1) O(1),只需要常数的空间存放若干变量。
题目来源:力扣。
放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我LeetCode主页 / CSDN—力扣专栏,每日更新!