LeetCode137只出现一次的数字——位运算

题目

题目描述:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现三次。找出那个只出现一次的元素。

说明:你的算法应该具有线性时间的复杂度。你可以不使用额外的空间来实现吗?

思路

题目要求线性复杂度,一般的算法做不到,不难想到用位运算。但怎么进行位运算,比较难想到。

b = (b ^ x) & ~a;
a = (a ^ x) & ~b;

^ 相当于除去原有元素,添加新元素, a &~  b 相当于从a集合中除去b集合中的所有元素。

int len = nums.size();
for(int i =0;i < len;++i)
{ b
= (b ^ nums[i]) & ~a; a = (a ^ nums[i]) & ~b;
}

出现一次的存在b中,第二次出现从b中清除同时会存在a中,第三次出现会从b中清除。最终出现一次的都存在b中,出现两次的都存在a中

例如:[1,2,2,1,1,2,99]

b={0} {1} {1,2} {1} {0} {0} {0} {99}
a={0} {0} {0} {2}

{1,2}

{2 {0} {0}

代码

 1 class Solution {
 2 public:
 3 int singleNumber(vector<int>& nums) {
 4     int a = 0, b = 0;
 5     for (auto x : nums) {
 6         a = (a ^ x) & ~b;
 7         b = (b ^ x) & ~a;
 8     }
 9     return a;
10 }
11 };
12 
13 static const auto __lamda = []() {
14     std::ios::sync_with_stdio(false);
15     std::cin.tie(nullptr);
16     return nullptr;
17 }();

续:

朋友面试竟然遇到了,前面的算法很讲究技巧性,不通用,补充一个较通用的方法:

int数组,32位,用一个32位的int数组,每一位记录值在该位出现1的次数。

其余元素出现3次,最后加起来肯定 %3 = 0。剩下的就是只出现一次的。

int bits[32];

int singleNumber(vector<int>& nums)
{
    int res = 0;
    for(int i = 0;i <32;i++)
    {
        for(int j = 0;j < nums.size();j++)
        {
            bits[i] += (nums[j]&1);
            nums[j] >>= 1;
        }
    }

    for(int i = 0;i < 32;i++)
        if(bits[i] % 3) res += (1 << i);

    return res;
}

参考链接:

1. https://leetcode-cn.com/problems/single-number-ii/comments/

2. https://www.cnblogs.com/fanguangdexiaoyuer/p/11585950.html

原文地址:https://www.cnblogs.com/lfri/p/10349846.html