在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
示例 1:
输入:nums = [3,4,3,3]
输出:4
示例 2:输入:nums = [9,1,7,9,7,9,7]
输出:1
限制:
1 <= nums.length <= 10000
1 <= nums[i] < 2^31来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-ii-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
首先我们可以采用map映射的方法,统计所有元素出现的次数,然后将出现次数为1的数据返回。但是同样,这种算法虽然能够完成任务,但是非常低效。
- class Solution {
- public:
- int singleNumber(vector<int>& nums) {
- map<int ,int> record;
- for(auto num:nums)
- {
- record[num]++;
- }
- for(auto num:nums)
- {
- if(record[num]==1)
- {
- return num;
- }
- }
- return 0;
- }
- };

这里我们可以采用这样的方法,就是统计全部数据的每一个二进制位上1的个数,然后全部都对3取模。因为我们从题目中知道,只有一个数据出现了一次,其余的数据全部都出现了三次,所以对三取模就相当于将这三个相同的数据全部都抵消掉了,而剩下的恰好就是那个仅出现了一次的数据
| 1 | 3 | 3 | 3 | 4 | 4 | 4 |
| 001 | 011 | 011 | 011 | 100 | 100 | 100 |
上面是我们的样例数据,从中我们可以观察到就1出现了一次,其余的3和4都出现了三次,此时我们分别将二进制位从右往左数第三位的全部数据相加,第二位的全部数据相加,第一位的全部数据相加
| 1 | 001 |
| 3 | 011 |
| 3 | 011 |
| 3 | 011 |
| 4 | 100 |
| 4 | 100 |
| 4 | 100 |
从上面这张表格中,我们可以很清晰地看出从右往左第三位全部相加是3,第二位全部相加是3,第一位全部相加是4,然后我们分别对这些相加的结果取模,就会得到0,0,1, 将这三位拼接起来就是001,也就是我们上面仅出现了一次的数据元素1。
- class Solution {
- public:
- int singleNumber(vector<int>& nums) {
- //创建一个大小为32的容器
- //因为我们一个int的大小是4个字节,每个字节又是8个比特位
- vector<int>binary_digit(32);
- //遍历我们的数据
- for(int i=0;i
size();i++) - {
- //point为我们当前所计算的是第几位的数据
- int point=0;
- //将我们容器中当前位置的数据拷贝出来
- int tmp=nums[i];
- //循环遍历,将这个数据转化成二进制位,然后每一位都加到对应的
- //binary_digit位上
- while(tmp)
- {
- binary_digit[point]+=tmp%2;
- //右移一位,获取下一个比特位的数据
- tmp=tmp>>1;
- //point++,准备存储下一个比特位的数据
- point++;
- }
- }
-
- //result就是我们要返回的结果
- int result=0;
- //遍历我们的二进制的容器元素,分别将其中的每一位都对3取模,
- //然后将每一位从前到后拼接起来,组成我们的结果
- for(int i=0;i
size();i++) - {
- result+=(binary_digit[i]%3)*(1<
- }
- return result;
- }
- };