Given an array of integers, every element appears three times except for one, which appears exactly once. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
First think
we record each bits occurrence
for example 2 2 2 3 0010 0010 0010 0011
should be
0 0 4 1
and then for each occurrence mod 3 -> 0 0 1 1 and this is the result.
since we do not want to use extra space, we need to use bit to represent the number,
1 bit can represent 0 , 1
2 bit can represent 00 01 10 11 that is from 0 - 3 which is enough since we only need 0 - 2 because i % 3 could only be 0 ,1 or 2
we use two number to store the occurrence, i2 stores the first bot and i1 stores the last bit.
simulating 0010 0010 0010 0011
i2 0 0 0 0
i1 0 0 0 0
when 0010 come
i2 0 0 0 0
i1 0 0 1 0
when 0010 come
i2 0 0 1 0
i1 0 0 0 0
when 0010 come
i2 0 0 1 0
i1 0 0 1 0
and we need to mod 3
i2 0 0 0 0
i1 0 0 0 0
when 0011 come
i2 0 0 0 0
i1 0 0 1 1
return i1
by doing the calculation
if i1[k] == n[k]: newi1[k] = 0, otherwise newi1[k] = i1[k]
newi1 = i1 ^ n
and we need to compute the carry for i2 to add. if carry[k] == 1 it means i1[k] = 1 && newi1[k] = 0
carry = i1 & (~newi1)
newi2 = carry ^ i2
then we need to mod 3 for each digit, which digit should be change? that newi1 ^ newi2 == 1
int tpminus = newi1 ^ newi2;
i1 = newi1 - tominus, i2 = newi2 - tominus.
return i1.
code:
public class Solution {
public int singleNumber(int[] nums) {
//i2 i1
int i1 = 0;
int i2 = 0;
for(int n : nums){
int newi1 = i1 ^ n;
int carry = i1 & (~newi1);
int newi2 = i2 ^ carry;
int minus = newi1 & newi2;
i1 = newi1 - minus;
i2 = newi2 - minus;
}
return i1;
}
}