https://oj.leetcode.com/problems/single-number-ii/
Given an array of integers, every element appears three times except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
解题思路:
这道题和Single Number很相像,Single Number是从一堆数字中,找出只出现一次的数字,其他数字都出现两次。根据XOR的性质,A^A = 0,0^A=A,A^B^A=A^A^B=B;从头到尾XOR一次就能找出那个出现一次的数字。
不过这次其他数字都出现三次,就不能用这个方法了。
同样可以考虑用hashmap计数,需要时间复杂度O(n),不过空间复杂度也达到了O(n)。
这里利用XOR的另一个性质。N个数字按位XOR可以看作是,把他们按位十进制相加后,取2的模。那么同样,这个题目就是按位十进制相加后,取3的模。那么出现3次的位就会变为0,即清空了,仅仅剩下出现1次的位数。然后再把他十进制复原出来即可。
以上结论具体可以参见网页:http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/xor.html。
public class Solution { public int singleNumber(int[] A) { int[] array = new int[32]; int signal = 0; for(int i = 0; i < A.length; i++){ int temp = A[i] > 0 ? A[i] : -A[i]; if(A[i] < 0){ signal = (signal + 1) % 3; } int j = 0; do{ array[j] += temp % 2; temp = temp /2; j++; }while(temp > 0); } for(int i = 0; i < 32; i++){ array[i] = array[i] % 3; } int result = 0; for(int i = array.length - 1; i >= 0 ; i--){ result = result * 2 + array[i]; } if(signal == 1){ result = 0 - result; } return result; } }
上述的解法没有用到位移的运算,采用/2取余数的方法,在针对都是正数的情况下可以得出结果。对于负数,需要区别对待。那么对于Integer.MIN_VALUE,拿掉符号变成正数就越界了,很难处理。
带着符号的按位右移,可以比较好的解决这个问题,将正负数一起解决了。
public class Solution { public int singleNumber(int[] A) { int[] array = new int[32]; int signal = 0; for(int i = 0; i < A.length; i++){ //int temp = A[i]; //int j = 0; //do{ // array[j] += temp & 1; //temp = temp >> 1; //if(temp == 0){ // break; //} //j++; //}while(temp > 0); for(int j = 0; j < 32; ++j) { int rotated = A[i]>>j; if(rotated == 0) break; array[j] += rotated & 1; } } for(int i = 0; i < 32; i++){ array[i] = array[i] % 3; } int result = 0; for(int i = 0; i <32 ; i++){ result += array[i] << i; } return result; } }