java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846 |
---|
与运算取末尾1分组
解题思路:时间复杂度O(
n
n
n),空间复杂度O(
1
1
1) |
---|
- 数组中有两个元素a和b出现1次,剩余都出现2次
- 通过异或操作,将出现2次的都抵消掉,获得两个出现一次的数的异或结果a^b
- 我们知道a^b的结果是,两者二进制中,值不同的位 = 1,相同的 = 0.
- 我们拿到a^b的最右边一个1,也就是a和b最右边的不相同的一位rightOne。也就是说rightOne位置,a的二进制和b的二进制不同,一个1,一个0
获取a的二进制最右边的1的经典操作办法是 rightOne = a & (-a).如果不懂,可以参考下面文章中,与运算的讲解
位运算https://blog.csdn.net/grd_java/article/details/136119268 |
---|
- 既然我们拿到了rightOne。他的二进制形式是整个二进制串,只有一个1,例如00000
1
0000,而这个1的位置,是区分a和b的关键,因为a和b中,只有一个在rightOne的位置是1.而另一个一定是0. 因为a^b后,1的位置代表a和b不同的位置 - 这样我们将整个数组分成两组,在rightOne位置为1的,和在rightOne位置为0的
- 然后我们对在rightOne位置为1的所有数字,进行异或统计。其中出现两次的数字,二进制不会有什么改变,在rightOne位置的二进制都一样。所以异或过程中,依然会抵消掉。最终结果会剩下出现一次的数字。a和b的一员。
这里假设为a。
因为a和b只有一个在rightOne位置是1,这里假设a在rightOne位置是1.而a只出现1次,其它在rightOne位置是1的数都出现两次。异或后都会抵消。最终只剩下a
- 这样我们就找到了一个出现一次的数字a。然后我们还有a^b的结果,我们将
a^b^a = (a^a)^b = 0^b = b
.这样就找到了a和b。返回即可。
class Solution {
public int[] singleNumber(int[] nums) {
int eor1 = 0;
for (int num : nums) eor1 ^= num;
int RightOne = eor1 & (-eor1);
int eor2 = 0;
for (int num : nums) {
if ((num & RightOne) == 0) {
eor2 ^= num;
}
}
return new int[] { eor2, eor1 ^ eor2 };
}
}