原题链接:
http://oj.leetcode.com/problems/single-number/
这道题目跟 Single Number II 比较类似,区别只是这道题目每个元素出现两次,而不是三次。我们仍然可以按照 Single Number II 中的两种方法来,都只是把取余3改成取余2即可。我们就列举一下第二种方法的代码如下:
按照上面的方法,虽然空间复杂度是O(1)的,不过还是需要一个32个元素的数组。还有另一种方法是利用每个元素出现两次,以及位操作异或的性质来解决这个问题。因为两个相同的元素异或结果是0,利用这个特点我们可以对所有数组元素进行异或,如果出现两次的元素就会自行抵消,而最终剩下的元素则是出现一次的元素。这个方法只需要一次扫描,即O(n)的时间复杂度,而空间上也不需要任何额外变量,比起上面的方法更优。代码如下:
这道题目跟 Single Number II 比较类似,区别只是这道题目每个元素出现两次,而不是三次。我们仍然可以按照 Single Number II 中的两种方法来,都只是把取余3改成取余2即可。我们就列举一下第二种方法的代码如下:
public int singleNumber(int[] A) {
int[] digits = new int[32];
for(int i=0;i<32;i++)
{
for(int j=0;j<A.length;j++)
{
digits[i] += (A[j]>>i)&1;
}
}
int res = 0;
for(int i=0;i<32;i++)
{
res += (digits[i]%2)<<i;
}
return res;
}
上面方法的时间复杂度仍然是O(n),空间是一个32个元素的数组,是O(1)的复杂度。
按照上面的方法,虽然空间复杂度是O(1)的,不过还是需要一个32个元素的数组。还有另一种方法是利用每个元素出现两次,以及位操作异或的性质来解决这个问题。因为两个相同的元素异或结果是0,利用这个特点我们可以对所有数组元素进行异或,如果出现两次的元素就会自行抵消,而最终剩下的元素则是出现一次的元素。这个方法只需要一次扫描,即O(n)的时间复杂度,而空间上也不需要任何额外变量,比起上面的方法更优。代码如下:
public int singleNumber(int[] A) {
if(A==null || A.length==0)
return 0;
int res = A[0];
for(int i=1;i<A.length;i++)
{
res ^= A[i];
}
return res;
}
上面的方法实现非常简练,不过也相当取巧,可能没有准备过比较难在面试中想到。相对而言第一种方法是比较通用的,无论出现多少次都是适用的。第二种方法属于对于出现两次这种特殊情况才能使用,不过方法巧妙,有点体现位运算的精髓,所以个人还是挺喜欢的哈。