LeetCode | Single Number
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; } }