Given an array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
数组是打乱的,除了一个数是单个,其余的出现2次。
这个题目有几个办法:
1. 32位数组存放
这里的整数都是32位的,所以创建一个新的32位定长数组,用来存放统计整数们的每一位来得到的次数。如果数组重复2次,那么数组对应的二进制里每一位也重复了2次。统计完对每一位都取余2,剩余的就是只出现1次的。
public int SingleNumber3(int[] A)
{
int[] bits = new int[32];
for (int i = 0; i < 32; i++)
{
for (int j = 0; j < A.Length; j++)
{
bits[i] += (A[j] >> i)&1;
}
}
int result = 0;
for (int i = 0; i < 32; i++)
{
result += (bits[i] % 2) << i;
}
return result;
}
运算符 类别 示例表达式 结果
>> 二元 var1 = var2 >> var3; 把var2 的二进制值向右移动var3 位,就得到var1 的值
<< 二元 var1 = var2 << var3; 把var2 的二进制值向左移动var3 位,就得到var1 的值
每向左<<移动一位,该数都要乘以2,
而每向右>>移动一位,则是给操作数除以2,并丢弃非整余数
2.c#位运算^
异或操作的规则:1^1=0,0^0=0 1^0=1 即:两个相同的数进行异或会得到0,并且任何一个数与0的异或还是原数. 不论整数是正的还是负的都可以用这个办法。这个方法只需要一次扫描,即O(n)的时间复杂度,而空间上也不需要任何额外变量,比起上面的方法更优。满足了要求”不要用额外空间来实现“。
public class Solution {
public int SingleNumber(int[] A) {
int result=0;
for(int i=0;i<A.Length;i++)
result^=A[i];
return result;
}
}
这个办法的前提条件(1)其余都出现2次,可以异或成0
如果题目改成其余数都出现3次,只有1个数出现1次呢?
3.hash table
这个题比较直接的想法是用一个HashMap对于出现的元素进行统计,key是元素,value是出现个数,如果元素出现三次,则从HashMap中移除,最后在HashMap剩下来的元素就是我们要求的元素(因为其他元素都出现三次,有且仅有一个元素不是如此)。这样需要对数组进行一次扫描,所以时间复杂度是O(n),而需要一个哈希表来统计元素数量,总共有(n+2)/3个元素,所以空间复杂度是O((n+2)/3)=O(n)。这个方法非常容易实现,就不列举代码了。