Given an array of integers, every element appears twice except for one. Find that single one.
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
题目:给定数组中除了一个特例只出现一次外,其他均出现两次
最基础的两重for循环算法:
//逻辑也是对的,但是为N方算法,提示Time Limit Exceeded,题目要求线性时间
public class Solution {
public int singleNumber(int[] A) {
if(A.length == 0) return -1;
if(A.length == 1) return A[0];
int result = -1;
for(int i=0; i<A.length; i++){
int count = 1;
for(int j=0; j<A.length; j++){ //对A[i]从A[0]开始试,用count计数A[i]在数组中出现的次数
if(A[j]==A[i]){ //注意:此处不能从j=i+1开始向后找,逻辑错误
if(i==j){ continue; } //自身相等,不算,continue对于if没影响
else{ count++; }
}
}
if(count!=2){ //如果不是2,就是要找的
result = A[i]; //break对if是没有影响的,用来跳出for循环
break;
}
}
return result;
}
}
利用xor,线性时间复杂度,且无需额外内存的算法:
利用异或XOR来实现,xor的三个特性:【注意对int型的xor运算是位运算,是转换为二进制进行逐位异或求解的】
(1)a^b=b^a (2)a^a=0 (3)a^0=a
从上面三个个特性有:a^b^a = b^a^a = b^0 =b
继续向下推理:N个数进行异或,其顺序是无关的,可以任意变换,而只要其中有两个数相同,就能改变次序形成a^a=0,又b^0=b,那么这两个相同的数对最终的异或结果没影响
此题说数组中只有一个数字出现一此,其他都出现两次,则必有:A[0]^A[1]^A[2]^...^A[N]=result
(不仅仅是出现两次,只要是满足出现偶数次,然后找例外出现奇数次都能用异或位运算来找到)
public class Solution {
public int singleNumber(int[] A) {
for(int i=A.length-1; i>0; i--)
A[i-1] ^= A[i]; //实际的效果就是在A[0]处进行所有数组元素的异或运算
return A[0];
}
}
扩展:求int[] A的sum
for(int i=A.length-1; i>0; i--)
A[i-1] += A[i];
return A[0];
利用Java容器类Map<key, value>实现的O(2N)算法:
//Map<key,value> = Map<A[i],count>
//利用map来统计数组中各元素出现的次数,只须遍历一次数组就能统计完毕,在利用iterator迭代map找到result
//算法为O(N)+O(N),符合题目要求的线性时间复杂度,只不过需要额外内存
public class Solution {
public int singleNumber(int[] A) {
int result = 0;
Map<Integer,Integer> hashMap = new HashMap<Integer,Integer>();
for(int i=0; i<A.length; i++){
if(hashMap.containsKey(A[i])){
hashMap.put(A[i],hashMap.get(A[i])+1);
}else{
hashMap.put(A[i],1);
}
}
Iterator<Map.Entry<Integer,Integer>> iterator = hashMap.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<Integer,Integer> entry = iterator.next();
if(entry.getValue()!=2){
result = entry.getKey();
break;
}
}
return result;
}
}