single_number
题意: 给定一个整数类型数组,除了一个元素之外其他所有元素均出现两次,找出这个唯一的元素。
条件: 要求线性时间复杂度,并且不适用额外空间
分析: 本题非常经典,在《剑指offer》中也出现过,用到的方法是位运算中的异或操作。记录每一bit出现的次数。由于两个相同的整数做异或一定是0,所以数组中重复的整数异或之后也是0,遍历数组时两两异或,最后异或后的结果就是那个唯一值。(该方法非常经典,要牢记)
代码
public int singleNumber(int[] A) {
if(A == null){
return Integer.MIN_VALUE;
}else{
int length = A.length;
int result = 0;
for(int i = 0; i < length; i++){
result ^= A[i];
}
return result;
}
}
single_number_II
题意: 给定一个整数类型数组,除了一个元素之外其他所有元素均出现三次,找出这个唯一的元素。
条件: 要求线性时间复杂度,并且不适用额外空间
分析: 由于本题重复值出现三次,不能直接使用异或操作。既然一个二进制位不够,那我们不妨用两个二进制位来表示出现次数。为此,定义几个变量
one
,
two
,
three
,
one
表示某个位只出现一次,
two
表示某个位出现过两次,
three=one
&
two
,
three
主要用来归零,只要出现过三次,就将
one
和
two
改为0(和single_number不同的是,single_number出现两次就归零,所以异或可以完成,single_number_II出现三次归零)。最后返回
one
即可。(该方法同样非常巧妙,抓住了该题的本质)
代码
public int singleNumber(int[] A) {
if(A == null){
return Integer.MIN_VALUE;
}else{
int one = 0; //出现过一次的位
int two = 0; //出现过两次的位
int three = 0; //出现过三次的位
for(int i = 0; i < A.length; i++){
int a = A[i];
two |= one&a; //先修改two
one ^= a; //再修改one
three = one&two; //one和two相应位置都是1的表示出现过3次
one &= ~three; //出现过3次的位在one和two中都修正回0
two &= ~three;
}
return one;
}
}
single_number改
题意: 给定一个整数类型数组,除了两个元素之外其他所有元素均出现两次,找出这个唯一的元素。本题将只有一个唯一的编程有两个唯一的,其余均出现过两次
分析: 本题依然先用异或,但是异或后的结果是两个数叠加后的值,这该如何求解?异或后的结果是一个32位的整数(JAVA中int是32位),从最后一位开始向左找到第一个1出现的位置,那么这两个数在该位(bit)上的值一定不同(否则就变为0),那么可以根据这一位是0或者1将数组一分为二,前一个数组在该位上均是0,后一个数组载该位上均是1; 两个唯一的值肯定一个在前一个数组中,一个在后一个中。然后分别对两个数组求异或,两个数组中的唯一值都只有一个了,就变成single_number问题了!(how unimaginable we can solve problem use this way, and it is crazy who can come up with this settlement!),原谅我自己也没实现这个方法,读者自行解决吧~