views:

626

answers:

8

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

+6  A: 

"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, 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
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
A: 

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
The problem is that this isn't O(n). Sorting is O(log n).
Glenn
Sure, this won't use any extra space, but will run in O(log n) time, since the sort will take you O(log n)
a_m0d
Sorting is O(n log n), not O(log n).
Steve Jessop
O(log n) is so much better than O(n)... too bad onbyone got it right...
Martinho Fernandes
Sorting is O(N). COMPARISON sort is O(n log n), but there's no need to use a compare sort for this. These aer numbers so you can use an O(N) inplace sort like a radix sort.
SPWorley
A: 

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
I think you meant `del hash[number]`.
Seth
+22  A: 

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
+1 - best answer. O(n) time, and O(1) extra space!
rampion
and one liner: `array.inject(0) { |accum,number| accum ^ number }`
rampion
Hey, that is clever! +1, xors are so cool.
rascher
<troll> I wouldn't've expected bitwise savvy from a *ruby* programmer</troll> *ducks*
rascher
Equivalent Python one-liner: `def singleton(array): return reduce(lambda x,y:x^y, array)`
Adam Rosenfield
We love you over in Ruby-land, rascher. Come, join us, we will absolve you.
Michael Sofaer
@Michael - the word is absorb - resistance is futile ;)
rampion
I think once anyone claims that they can absolve someone, they probably also have absorption in mind.
rascher
I'm "code golfing", in Haskell: `singleton = foldr xor 0`
Martinho Fernandes
A: 

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.

Adam Rosenfield
+7  A: 

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, O(n) performance, and O(1) extra space (just one tiny little integer).

paxdiablo
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
I'll yield to your judgment on that one, @Doug - I haven't done that level of math for over 20 years :-)
paxdiablo
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
+1  A: 

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
A: 

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