题目描述如下:
Given a non-empty array of integers, every element appears three times except for one, which appears exactly once. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
Example 1:
Input: [2,2,3,2] Output: 3
Example 2:
Input: [0,1,0,1,0,1,99] Output: 99
数组里除了一个数字外其他都出现了3次,找出该出现一次数字
不动脑的简单解法很简单,
用map之类的一次遍历统计出现次数,再遍历map筛出出现次数为1的那个数字。但该方法用了额外的存储空间
int singleNumber(vector<int>& nums) {
map<int,int>dict;
for(auto i : nums)
{
if(dict.find(i)!=dict.end())
++dict[i];
else
dict[i] = 1;
}
for(auto beg = dict.begin();beg!=dict.end();++beg)
{
if(beg->second == 1)
return beg->first;
}
return 0;
}
做一次原地排序,比较一下左右两个数字和自己的相等关系,某个数字左右都不和自己相同显然就是了,但该方法时间复杂度并不是线性
int singleNumber(vector<int>& nums) {
sort(nums.begin(),nums.end());
if(nums[0]!= nums[1])
return nums[0];
if(nums[nums.size()-1] != nums[nums.size()-2])
return nums[nums.size()-1];
//边界判断
for(int i = 1; i < nums.size()-1;++i)
{
if(nums[i]!=nums[i-1]&& nums[i]!=nums[i+1])
return nums[i];
}
}
以上2个方法显然不是该题目所要考察的,该题目希望考察的是位运算,回顾该系列题目的第一道,题目要求变成其他的变成了2次,第一道的做法是 挨个进行亦或,其原理是相同的数字进行亦或就为0,而任何数字和0亦或为原先的数字。
显然该题好像和亦或没什么关系,但带来了启示,其做法应该是与每个数字的位有关。
该题目所用int应为32位的整型,那么有 以 3 5 5 5 为例,
该4个数的2进制为:
0011
0101
0101
0101
从最低位看,4个数的最低为count 为4,第二位为 1,第三位2,第四位为0,若count%3 != 0,就把该为作为结果位的答案的话,结果就为: 0011,正好就是我们所需要筛出来的答案
为何?其原理就是在某个位上,该位上的count自然要么 为3N,或3N+1(N代表重复的数),若为3N自然表示出现在该位的都是重复数字,3N+1中的那个1就是不重复的,代码如下:
int singleNumber(vector<int>& nums) {
int result = 0;
for(int i = 0; i <32;++i)
{
int mask = 1<<i; //从最低位,挨个筛出相应位
int count = 0;
for(auto num : nums)
{
if((num&mask) != 0 )
++count;
}
if(count%3==1)
result |= mask; //结果的相应位就置为1
}
return result;
}