剑指 Offer 56 - I. 数组中数字出现的次数
题目:
给定数组,含有两个只出现一次的数字,其余均出现两次。请找出这两个数字,时间O(n),空间O(1)
解法:
空间O(1)完全去除了计数的做法,偷偷看标签知道这是位运算题,立刻想到异或。将所有数字异或起来得到两个单独数字的异或,可惜没有进一步的方法把这两个数字找出来。
再偷偷看题解知道要用分组异或。只需要确保一对数字肯定在一个组,单独数字在不同组即可。正常的奇偶分组方式是看最右边一位,这边需要找到一位,单独的数字不同而成对的数字相同。
后半段肯定成立,所以我们只需要找到一位,单独的数字这一位不同。利用异或结果即可。
如何找出这一位呢?可以用1循环左移位得到mask,更快的方法是a&(-a),这是为什么呢?我们以任意有符号整数来说,10000...是最大的负数,取负的结果还是自身。可知1后面跟一串0的性质是取负不变。所以对于任意整数,取负以后会保留最右边10*(这边用正则表示)不变,左边剩余取反。那自然a&(-a)会保留右边10*的那个1,其余都是0。
代码:
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int a = 0, b = 0, c = 0;
for(int &i: nums)
a ^= i;
int mask = a & -a;
for(int &i: nums)
mask & i ? b ^= mask : c ^= mask;
vector<int> ans = { b,c };
return ans;
}
};