题目:
Given an array of integers, every element appears three times except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
注意:
算法要有线性时间复杂度。能做到不适用额外的内存吗?
思路:
本题依然使用位运算。首先思考,计算机是怎么存储数字的。即二进制,考虑把一个整数表示成32位的二进制数,定义一个32个数的数组,保存某个整数二进制形式的第i位,比如说十进制数10,二进制形式是00000000 00000000 00000000 00001010,如果这个数出现三次,把它们对应的第i位的和存储到数组中。如果是3的倍数,说明这个数出现了3次。比如说出现了3次10,那么结果就是0000000000000000 00000000 00003030。如果对所有的数的第i为求和并保存到数组中,再对数组中的所有数 % 3 ,那么最后数组中的数就是只出现一次的数的二进制位。
代码:
class Solution {
public:
int singleNumber(int A[], int n)
{
int result = 0 ;
int count[32] = {0};
for(int i = 0 ; i < 32 ; i++)
{
for(int j = 0 ; j < n ; j++)
{
//把所有数的二进制形式的第i位取出来((A[j] >> i) & 1)并求和
count[i] += (A[j] >> i) & 1;
}
count[i] %= 3;
}
for(int i = 0 ; i < 32 ; i++)
{
result += (count[i] << i);
}
return result;
}
};
这个算法是有改进的空间的,可以使用掩码变量:
ones 代表第i th 位出现一次的掩码变量
twos 代表第i th 位出现两次的掩码变量
threes 代表第i th 位出现三次的掩码变量
假设在数组的开头连续出现3次5,则变化如下:
ones = 101
twos = 0
threes = 0
--------------
ones = 0
twos = 101
threes = 0
--------------
ones = 0
twos = 0
threes = 101
--------------
class Solution {
public:
int singleNumber(int A[], int n)
{
int ones = 0, twos = 0, threes = 0;
for (int i = 0; i < n; i++)
{
twos |= ones & A[i];//出现1次的结果再与A[i] 取与的结果就是出现2次的结果
ones ^= A[i];// 出现一次的结果
//对于ones 和 twos 把出现了3次的位置设置为0
//如果ones和twos中的一个为0,则three为0
threes = ones & twos;
ones &= ~threes;
twos &= ~threes;
}
return ones;
}
};