19

What I can think of is:

Algo:

  1. Have a hash table which will store the number and its associated count
  2. Parse the array and increment the count for number.
  3. Now parse the hash table to get the number whose count is 1.

Can you guys think of solution better than this. With O(n) runtime and using no extra space

Cœur
  • 37,241
  • 25
  • 195
  • 267
Learner
  • 2,556
  • 11
  • 33
  • 38

9 Answers9

45

Assuming you can XOR the numbers, that is the key here, I believe, because of the following properties:

  • XOR is commutative and associative (so the order in which it's done is irrelevant).
  • a number XORed with itself will always be zero.
  • zero XORed with a number will be that number.

So, if you simply XOR all the values together, all of the ones that occur twice will cancel each other out (giving 0) and the one remaining number (n) will XOR with that result (0) to give n.

r = 0
for i = 1 to n.size:
    r = r xor n[i]
print "number is " + r

No hash table needed, this has O(n) performance and O(1) extra space (just one tiny little integer).

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 3
    Commutativity alone isn't enough to prove that "the order in which it's done is irrelevant." For that you also need associativity. Conveniently, XOR is also associative. To see why you need both, consider the (commutative!) pairwise average function: average(average(2, 4), 8) = 5.5, but average(2, average(4, 8)) = 4. – Doug McClean Jul 07 '09 at 03:20
  • 1
    I'll yield to your judgment on that one, @Doug - I haven't done that level of math for over 20 years :-) – paxdiablo Jul 07 '09 at 03:37
  • 2
    Assuming that the "number" behaves as a POD this will work regardless of how it is implemented inside - will work even for floating point numbers if they are read as blocks of raw data. Excellent solution. – sharptooth Jul 07 '09 at 10:26
  • Does this technique work for negative numbers as well? I tried for {-1, -1, -2} and it returned 3 instead of -2! – Hengameh May 03 '15 at 05:37
  • 1
    @Hengameh: then whatever language you're using doesn't `xor` properly, or you're printing out incorrectly. You should ask a question, showing your code and specifying your language. That way, you'll get a broader response than from only me. – paxdiablo May 03 '15 at 05:50
34

An answer in Ruby, assuming one singleton, and all others exactly two appearances:

def singleton(array)
  number = 0
  array.each{|n| number = number ^ n}
  number
end

irb(main):017:0> singleton([1, 2, 2, 3, 1])
=> 3

^ is the bitwise XOR operator, by the way. XOR everything! HAHAHAH!

Rampion has reminded me of the inject method, so you can do this in one line:

def singleton(array) array.inject(0) { |accum,number| accum ^ number }; end
Michael Sofaer
  • 2,927
  • 24
  • 18
13

"Parse the array and increment the count for number."

You could change this to "Parse the array and if the number already exists in the hash table, remove the number from the hash table". Then step 3 is just "get the only number that remains in the hash table"

Chris J
  • 1,375
  • 8
  • 20
  • +1, not sure why you were down-voted. Seems perfectly reasonable to me. Finding an item in a hash and deleting an item from a hash should both be O(1). – Seth Jul 07 '09 at 02:02
  • O(1)? you have to consider resizing (http://en.wikipedia.org/wiki/Hash_table ). I suggest use .resize() in the very beginning, as you know the size of array. Anyhow, the solution with XORs is more efficient. – MadH Jul 07 '09 at 09:47
  • 3
    +1 when talking about things like job interview, this is actually preferable way of solving this problem. IMO, `XOR`ing is just too smart to be the first thing to come to interviewee's mind – illegal-immigrant Jun 25 '14 at 07:48
6

Given an array of integers, every element appears twice except for one. Find that single one. We can use XOR operation. Because every number XOR itself, the results will be zero. So We XOR every integer in the array, and the result is the single one we want to find. Here is the java version code:

public class Solution {
    public int singleNumber(int[] A) {
        int res=0;
        for(int i=0;i<A.length;i++){
            res=res^A[i];
        }
        return res;
    }
}

Follow up 1: 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? For this problem, we can't use the XOR operation.The best way to solve this problem is use "bit count". Create a 32 length int array count[32]. count[i] means how many '1' in the ith bit of all the integers. If count[i] could be divided by 3, then we ignore this bit, else we take out this bit and form the result.Below is java version code:

public class Solution {
    public int singleNumber(int[] A) {
        int res=0;
        int[] count=new int[32];
        for(int i=0;i<32;i++){
            for(int j=0;j<A.length;j++){
                if(((A[j]>>i)&1)==1){
                    count[i]=count[i]+1;
                }
            }
            if((count[i]%3)!=0){
                res=res|(1<<i);
            }
        }
        return res;
    }
}

Follow up 2: Given an array of integers, every element appears twice except for two. Find that two integers. Solution: First, XOR all the integers in the array we can get a result.(suppose it's c) Second, from the least significant bit to the most significant bit, find the first '1' position(suppose the position is p). Third, divided the integers in to two groups, the p position is '1' in one group, '0' in other group. Fourth, XOR all the integers in the two groups, and the results is the two integers we want.

jerry
  • 61
  • 1
  • 2
2

I'm stealing Michael Sofaer's answer and reimplementing it in Python and C:

Python:

def singleton(array):
    return reduce(lambda x,y:x^y, array)

C:

int32_t singleton(int32_t *array, size_t length)
{
    int32_t result = 0;
    size_t i;
    for(i = 0; i < length; i++)
        result ^= array[i];
    return result;
}

Of course, the C version is limited to 32-bit integers (which can trivially be changed to 64-bit integers if you so desire). The Python version has no such limitation.

Community
  • 1
  • 1
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • Does this technique work for negative numbers as well? I tried for {-1, -1, -2} and it returned 3 instead of -2! – Hengameh May 03 '15 at 05:46
2

Here's a solution in Python that beats the Ruby one for size (and readability too, IMO):

singleton = lambda x: reduce(operator.xor, x)
Nick Johnson
  • 100,655
  • 16
  • 128
  • 198
1

Python 3.1 Solution:

>>> from collections import Counter
>>> x = [1,2,3,4,5,4,2,1,5]
>>> [value for value,count in Counter(x).items() if count == 1 ][0]
3
>>> 
  • Paddy.
Paddy3118
  • 4,704
  • 27
  • 38
0

Algo 2:

  1. Sort the array.
  2. Now parse the array and if 2 consecutive numbers are not same we got our number.
  3. This will not use extra space
Learner
  • 2,556
  • 11
  • 33
  • 38
0

This doesn't fit the bill for "no extra space" but it will cut the space unless the numbers are sorted in a certain way.

In Python:

arr = get_weird_array()
hash = {}

for number in arr:
   if not number in hash:
     hash[number] = 1
   else:
     del hash[number]

for key in hash:
    print key
Andrew Johnson
  • 13,108
  • 13
  • 75
  • 116