*LeetCode--136. Single Number(异或运算,寻找单个的元素)
()题目大意:有一个数组,除了一个元素出现了一次,所有其他元素均出现了两次,求出这个元素。
题目要求时间复杂度O(n) , 空间复杂度O(1)
刚读完题,想到的是使用HashMap来看元素是否重复,时间复杂度为O(n),但是空间复杂度为O(1),不满足题意。
仍然给出代码:(如果元素在map内,则删除,否则,添加进去。这样到最后只有那个单个的元素)
public static int singleNumber(int[] nums) { HashMap<Integer,Integer> map = new HashMap(); int len = nums.length; for(int i = 0 ; i < len ; i++){ if(map.get(nums[i])!=null) map.remove(nums[i]); else map.put(nums[i], 1); } Set set = map.keySet(); Iterator itr = set.iterator(); return (int)itr.next(); }
正确解法:利用异或运算
异或运算:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
注意:
1. 异或运算是可交换,即 a ^ b = b ^ a
2. 0 ^ a = a
代码:
public static int singleNumber(int[] nums) { int len = nums.length; int solu = 0; for(int i = 0 ; i < len ; i++){ solu = solu^nums[i]; } return solu; }
参考资料:http://www.cnblogs.com/changchengxiao/p/3413294.html
本题扩展
1.一个数组中有两个元素只出现一次,其他所有元素都出现两次,求这两个只出现一次的元素
[解题思路]
将数组所有元素都进行异或得到一个不为0的结果,根据这个结果中的不为0的某一位将数组分成两组
将两组中的元素进行异或,如两个数组的异或值都不为0,则得到最后结果
如果有两个只出现一次的数字,设定为a,b。也是应用异或,但是数组元素全部异或的结果x=a^b,因为a,b是不相同的数字,因此x肯定不为0。对于x,从低位到高位开始,找到第一个bit位为1的位置设定为第m位,这个第m位的bit肯定来自a或者来自b,不可能同时a,b的第m位(从低到高位)都为1。这样,就可以根据这个第m位就可以把数组分为两个部分,一组为第m位为0,一组为第m位为1.这样,就把问题分解成了求两个数组中只出现一次的数字了
2.一个数组中有一个元素只出现1次,其他所有元素都出现k次,求这个只出现1次的元素
[解题思路]
当k为偶数时,同lss
当k为奇数时,将数组中每个元素转换成二进制,将对应的每一位相加mod k,得到结果即位出现1次的元素,时间复杂度O(n*len),空间复杂度为O(1)
这里以k=3为例:
//思路 : 将每一个数字转换成二进制数, //对应的每一位相加,三个相同的数,在该位上的和只可能是0或者3 //将每一位的结果和3取余,就相当于把出现3次的数字抵消了,那么这个剩下的数字就是单下来的那个数 public static int singleNumber(int[] nums) { int len = nums .length; int temp ; int res = 0; for(int i = 0 ; i < 32 ; i++){ temp = 0; for(int j = 0 ; j < len ; j++) temp = temp + ((nums[j]>>i)&1) ; res = res| (temp%3)<<i; } return res; }
注意:上面代码中对res的计算也可以表示成:
res+( (temp%3)<<i );
但是注意后半部分要加上括号。
上面这种方法是一种通用的解法。还有一种针对k=3的解法:
原文见:http://www.acmerblog.com/leetcode-single-number-ii-5394.html
ones代表第ith 位只出现一次的掩码变量 (这个最终代表结果)twos代表第ith 位只出现两次次的掩码变量 (出现两次的结果累计在这,注意不是加)threes代表第ith 位只出现三次的掩码变量 (出现三次的结果累计在这,注意不是加)
假设在数组的开头连续出现3次5,则变化如下:
01 ones = 101 02 twos = 0 03 threes = 0 04 -------------- 05 ones = 0 06 twos = 101 07 threes = 0 08 -------------- 09 ones = 0 10 twos = 0 11 threes = 101 12 --------------
当第 ith 位出现3次时,我们就 ones 和 twos 的第 ith 位设置为0. 最终的答案就是 ones。
int singleNumber(int A[], int n) { int ones = 0, twos = 0, threes = 0; for (int i = 0; i < n; i++) { twos |= ones & A[i]; ones ^= A[i];// 异或3次 和 异或 1次的结果是一样的 //对于ones 和 twos 把出现了3次的位置设置为0 (取反之后1的位置为0) threes = ones & twos; ones &= ~threes; twos &= ~threes; } return ones; }

浙公网安备 33010602011771号