在列表中find单个号码

什么是最好的algorithmfind一个数字只发生一次在一个列表中,其中所有其他数字发生了两次。

所以,在整数列表(让我们把它作为一个数组)每个整数重复两次,除了一个。 要find那个,最好的algorithm是什么。

最快的(O(n))和最有效的内存(O(1))方式是异或操作。

在C:

int arr[] = {3, 2, 5, 2, 1, 5, 3}; int num = 0, i; for (i=0; i < 7; i++) num ^= arr[i]; printf("%i\n", num); 

这将打印“1”,这是唯一一次出现的。

这是有效的,因为你第一次碰到一个数字时,它将自己标记为numvariables,而第二次它将自己标记为num(或多或less)。 唯一没有标记的是你的不重复。

顺便说一句,您可以扩展这个想法,以便在重复列表中快速find两个唯一的号码。

我们称之为独特的数字a和b。 首先采取一切的异或,凯尔build议。 我们得到的是a ^ b。 我们知道a ^ b!= 0,因为a!= b。 selecta ^ b中的任何1位,并将其用作掩码 – 更详细地说:selectx作为2的幂,使x&(a ^ b)非零。

现在将列表分成两个子列表 – 一个子列表包含y和x == 0的所有数字y,剩下的列在另一个子列表中。 顺便说一下,我们selectx,我们知道a和b在不同的桶中。 我们也知道每一副副本都在同一个桶里。 所以我们现在可以单独应用“XOR-em-all”技巧到每个桶,并且发现a和b是完全的。

巴姆。

O(N)时间,O(N)内存

HT =哈希表

HT.clear()遍历列表为了您看到的每个项目

 if(HT.Contains(item)) -> HT.Remove(item) else ht.add(item) 

最后,HT中的物品就是你正在寻找的物品。

注意(credit @Jared Updike):这个系统会查找所有Odd项目的实例。


评论 :我不明白人们如何投票给你NLogN性能的解决scheme。 哪个宇宙是“更好”? 我更震惊的是你标记了接受的答案是NLogN解决scheme…

但是我同意,如果内存需要保持不变,那么NLogN将是(迄今为止)最好的解决scheme。

凯尔的解决scheme显然不能捕捉到数据集不符合规则的情况。 如果所有数字都是成对的,那么algorithm会给出零的结果,如果零是唯一出现的唯一值,则完全相同的值。

如果有多个单独的发生值或三倍,则结果也是错误的。

对数据集进行testing可能最终会导致成本更高的algorithm,无论是在内存中还是在时间上。

Csmba的解决scheme确实显示了一些errouness数据(没有或多于一个单一的发生值),但没有显示其他(四元组)。 关于他的解决scheme,根据HT的实现,内存和/或时间多于O(n)。

如果我们不能确定input集的正确性,那么sorting和计数,或者使用散列表计数发生,而整数本身就是散列键,这两者都是可行的。

我会说,使用sortingalgorithm,然后通过sorting列表find号码是一个很好的方法来做到这一点。

现在问题是find“最好的”sortingalgorithm。 有很多sortingalgorithm,每个algorithm都有其强弱点,所以这是一个相当复杂的问题。 维基百科条目似乎是一个很好的信息来源。

在Ruby中的实现:

 a = [1,2,3,4,123,1,2,.........] t = a.length-1 for i in 0..t s = a.index(a[i])+1 b = a[s..t] w = b.include?a[i] if w == false puts a[i] end end 

你需要指定“最好”的意思 – 对某些人来说,速度就是最重要的,并且将答案限定为“最好的” – 对于其他人来说,如果解决scheme更具可读性,他们可能会原谅几百毫秒。

“最好”是主观的,除非你更具体。


那就是说:

遍历数字,每个数字search该数字的列表,当您达到search结果数量仅返回1的数字时,您就完成了。

似乎最好的办法是遍历列表,每个项目都将其添加到“已看到”项目列表中,或者如果它已经存在,则将其从“已看到”项目中移除,最后在列表中显示“已看到“项目将包括单数元素。 这是关于时间的O(n)和关于空间的关于n(在最坏的情况下,如果列表被sorting,将会好得多)。

事实上,他们是整数并不是真正的因素,因为没有什么特别的事情可以添加它们来做…在那里?

我不明白为什么select的答案是任何标准“最好的”。 O(N * lgN)> O(N),并且它改变列表(或者创build它的副本,这在空间和时间上仍然更昂贵)。 我错过了什么吗?

取决于数量有多大/多小。 基数sorting可能是适用的,这将大大减lessO(N log N)解决scheme的sorting时间。

sorting方法和XOR方法具有相同的时间复杂度。 如果您假定两个string按位“异或”是一个常量时间操作,则XOR方法仅为O(n)。 这相当于说数组中整数的大小是以一个常数为界。 在这种情况下,您可以使用基数sorting来sortingO(n)中的数组。

如果数字不是有界的,则按位XOR需要时间O(k),其中k是位串的长度,XOR方法取O(nk)。 现在基数sorting将在时间O(nk)sorting数组。

你可以简单地把集合中的元素放到哈希中,直到find一个碰撞。 ruby,这是一个单线。

 def find_dupe(array) h={} array.detect { |e| h[e]||(h[e]=true; false) } end 

所以, find_dupe([1,2,3,4,5,1])会返回1。

这实际上是一个常见的“技巧”面试问题。 它通常是关于一个重复的连续整数列表。 在这种情况下,面试官经常在寻找你使用n- integers技巧的高斯和,例如从实际总和中减去n*(n+1)/2 。 教科书的答案是这样的。

 def find_dupe_for_consecutive_integers(array) n=array.size-1 # subtract one from array.size because of the dupe array.sum - n*(n+1)/2 end