Algorithm to find a number which occurs only once in an array, given all the other numbers occur twice [duplicate]
Asked Answered
A

9

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

Almeda answered 7/7, 2009 at 1:43 Comment(5)
That's a pretty good solution with good efficiency.Bushwa
Is this a homework question? If it is, that's ok as you asked it well, with supplying your attempt at a solution. But you should tag it such if it is.Definitive
Btw, that word "parse". I don't think it means what you think it means.Pupa
why rosetta-stone ? BRadAlmeda
How on Earth did this get marked as a duplicate of a question that was asked six years later?Leap
U
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
Unbounded answered 7/7, 2009 at 1:53 Comment(9)
+1 - best answer. O(n) time, and O(1) extra space!Gourmont
and one liner: array.inject(0) { |accum,number| accum ^ number }Gourmont
Hey, that is clever! +1, xors are so cool.Capri
<troll> I wouldn't've expected bitwise savvy from a ruby programmer</troll> ducksCapri
Equivalent Python one-liner: def singleton(array): return reduce(lambda x,y:x^y, array)Parsimonious
We love you over in Ruby-land, rascher. Come, join us, we will absolve you.Unbounded
@Michael - the word is absorb - resistance is futile ;)Gourmont
I think once anyone claims that they can absolve someone, they probably also have absorption in mind.Capri
I'm "code golfing", in Haskell: singleton = foldr xor 0Gnosticism
L
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).

Leap answered 7/7, 2009 at 3:2 Comment(5)
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.Berky
I'll yield to your judgment on that one, @Doug - I haven't done that level of math for over 20 years :-)Leap
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.Secrecy
Does this technique work for negative numbers as well? I tried for {-1, -1, -2} and it returned 3 instead of -2!Monoplane
@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.Leap
U
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
Unbounded answered 7/7, 2009 at 1:53 Comment(9)
+1 - best answer. O(n) time, and O(1) extra space!Gourmont
and one liner: array.inject(0) { |accum,number| accum ^ number }Gourmont
Hey, that is clever! +1, xors are so cool.Capri
<troll> I wouldn't've expected bitwise savvy from a ruby programmer</troll> ducksCapri
Equivalent Python one-liner: def singleton(array): return reduce(lambda x,y:x^y, array)Parsimonious
We love you over in Ruby-land, rascher. Come, join us, we will absolve you.Unbounded
@Michael - the word is absorb - resistance is futile ;)Gourmont
I think once anyone claims that they can absolve someone, they probably also have absorption in mind.Capri
I'm "code golfing", in Haskell: singleton = foldr xor 0Gnosticism
I
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"

Immigrant answered 7/7, 2009 at 1:47 Comment(3)
+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).Cassius
O(1)? you have to consider resizing (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.Johnathanjohnathon
+1 when talking about things like job interview, this is actually preferable way of solving this problem. IMO, XORing is just too smart to be the first thing to come to interviewee's mindWeinhardt
C
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.

Cooee answered 27/12, 2013 at 2:33 Comment(2)
Really neat follow ups :)Goodness
Does this technique work for negative numbers as well? I tried for {-1, -1, -2} and it returned 3 instead of -2!Monoplane
P
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.

Parsimonious answered 7/7, 2009 at 2:8 Comment(1)
Does this technique work for negative numbers as well? I tried for {-1, -1, -2} and it returned 3 instead of -2!Monoplane
A
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)
Agriculturist answered 7/7, 2009 at 10:20 Comment(0)
N
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.
Northern answered 14/7, 2009 at 23:6 Comment(0)
A
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
Almeda answered 7/7, 2009 at 1:50 Comment(4)
The problem is that this isn't O(n). Sorting is O(log n).Amphithecium
Sorting is O(n log n), not O(log n).Pupa
O(log n) is so much better than O(n)... too bad onbyone got it right...Gnosticism
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.Balk
E
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
Eckhart answered 7/7, 2009 at 1:53 Comment(1)
I think you meant del hash[number].Cassius

© 2022 - 2024 — McMap. All rights reserved.