leetcode_137. 只出现一次的数字 II

一、题目内容

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,3,2]
输出: 3
示例 2:
输入: [0,1,0,1,0,1,99]
输出: 99
leetcode_137. 只出现一次的数字 II

二、题解思路

必备知识:这道题用到了|&>><<的操作,先来解释他们的含义
|:有1为1,没1位0,例如1101 | 1000 = 1101
&:都为1才是1,例如1101 & 1000 = 1000
>> 右移,例如2 >> 1 = 0010 >> 1 = 0100 = 4
<< 左移,例如2 << 1 = 0010 << 1 = 0001 = 1

逻辑原理:我们将所有的数看成是二进制位的数,先不考虑单独出现的那个数,用[2,2,3,2]来举例吧2换成2进制就是0010每个位置都相加
在这里插入图片描述
那如果该对应二进制上的数为1,那他们出现的次数一定是3的倍数,此时再把单独出现的那个数字加进去考虑
在这里插入图片描述
我们发现一个规律,如果每个对应的二进制为都模上3,结果肯定都是1或者0,如果结果为1,那它肯定是单独出现的那个数字二进制位上的。如果该数出现了3次、6次或者9次,模上3结果都为0,表示该单独的那个数字在该二进制位上并没有出现过,也就是该位置上为0。
在这里插入图片描述

代码实现原理(和代码一起看):每个数字都有32个比特位,所以我们循环32次,计算每个位上1出现的次数,里面再嵌套一个循环,用来遍历每个数,统计该位置上出现的次数。遍历时定义一个计数器,用于记录出现的次数,cnt+=(e>>i)&1先看等式右边,e>>i表示数字e右移i次后的结果,再与上1,1可以如果该位置上是1,那就加入到计数器cnt中。遍历完后,再看res|=(cnt%3)<<i看等式右边cnt%3表示看该位置上的1是否是单独出现的那个数字上的1,再用该结果左移i位,退回到原来二进制的位置,再看右边res|=用结果或上等式右边的结果。
在这里插入图片描述

三、代码

class Solution {
    
    
public:
    int singleNumber(vector<int>& nums) 
    {
    
    
        int res = 0;
        for (int i = 0; i < 32; ++i)
        {
    
    
            int cnt = 0;
            for (auto& e:nums)
            {
    
    
                //获取每个位上的个数
                cnt += (e >> i) & 1;
            }
            //模3再右移i,表示该数原本应该在的位置,再或上之前的结果
            res |= (cnt % 3) << i;
        }
        return res;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_44443986/article/details/115279679