137.SingleNumberII

你快乐吗?

Posted by bbkgl on September 26, 2019

137. Single Number II

C++,位运算。讲一个更容易理解的解法吧,复杂度是32 * O(n),也是符合题目要求的。热评大佬的解法我暂时没看懂。

只要是在int范围内,每个整数都是用32位二进制表示的。如果我们将nums中所有数都转成32位的二进制,并用一个size为32的数组bits表示每个位中1的个数,就能发现一件很巧妙的事情。

  • 有一些位的值,是3的倍数
  • 有一些位的值,不是3的倍数,且对3取模一定等于1
  • 不存在有值对3取模等于2

举个例子,nums = [5, 3, 3, 3],为了简单,我们用4位二进制表示,则nums = [0101, 0011, 0011, 0011]。根据刚才的规律和定义的bits的功能,我们得到bits应该是bits = [4, 3, 1, 0]。bits有如下规律:

  • bits[0, 2] % 3 == 1
  • bits[1, 3] % 3 == 0

然后我们直接把bits数组中能够整除3的值置0,不能整除3的值置1,就得到了一个表示二进制的整型数组。经过这个操作的bits为bits = [1, 0, 1, 0],用二进制来看就是0101,也就是5,正好是只出现一次的那个数。

这个规律不仅对本例适用,对所有例子都是适用的,这里我就不证明了,其实我也不会证明。。。

用这个规律解本题,只要实现三个操作就行了:

  • 用bits数组统计nums中所有数转化成二进制后,每个位上1的个数
  • 将bits数组中能够整除3的值置0,不能整除3的值置1
  • 将bits转换成真的二进制数

以上位运算以及具体操作在代码里实现了,思路写的比较详细,希望有所帮助:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        vector<int> bits(32);
        int ans = 0;
        for (int i = 0; i < 32; i++) {
            for (int j = 0; j < nums.size(); j++)
                bits[i] += (nums[j] >> i) & 1;
            ans |= (bits[i] % 3) << i;
        }
        return ans;
    }
};