您将获得一个整数介于1和1,000,000之间的数组。一个整数在数组中两次。你怎么决定哪一个?你能想出一种使用额外内存的方法吗?
Algo:
你们能想到更好的解决方案吗?
答案 0 :(得分:33)
这个问题有点含糊不清;当请求是“哪一个”时,是否意味着返回重复的值,或者重复的位置?如果是前者,以下三种解决方案中的任何一种都可以使用;如果是后者,第一个是唯一有帮助的。
构建位图;在迭代数组时设置 n 位。如果该位已设置,则表示您找到了重复项。它运行在线性时间,适用于任何大小的数组。
使用与数组中可能的值一样多的位来创建位图。在遍历数组时,检查数组中的 n 位。如果已设置,您已找到副本。如果不是,则设置它。 (这样做的逻辑可以在Bit arrays上的维基百科条目中的伪代码中看到,或者使用System.Collections.BitArray类。)
对数组进行排序,然后进行线性搜索,直到当前值等于之前的值。使用最少的记忆。用于改变排序算法以在比较操作期间检测重复并提前终止的加分点。
如果你同时计算总和,这几乎不需要额外的记忆,可以一次完成。
缺点是您需要完成整个循环才能找到答案。
优点是简单,实际上它比其他解决方案运行得更快的可能性很高。
答案 1 :(得分:9)
假设1到1,000,000之间的所有数字都在数组中,所有1到1,000,000之间的数字之和为(1,000,000)*(1,000,000 + 1)/2 = 500,000 * 1,000,001 = 500,000,500,000
。
所以只需将数组中的所有数字相加,减去500,000,500,000,你就会得到两次出现的数字。
O(n)时间和O(1)记忆。
如果假设不正确,您可以尝试使用Bloom Filter - 它们可以比哈希表更紧凑地存储(因为它们只存储存在的事实),但他们确实存在误报的风险。但是,通过我们选择在布隆过滤器上花费多少内存,这种风险可能会受到限制。
然后我们可以使用布隆过滤器在O(n)时间内检测潜在的重复项,并在O(n)时间内检查每个候选项。
答案 2 :(得分:6)
这个python代码是modification of QuickSort:
def findDuplicate(arr):
orig_len = len(arr)
if orig_len <= 1:
return None
pivot = arr.pop(0)
greater = [i for i in arr if i > pivot]
lesser = [i for i in arr if i < pivot]
if len(greater) + len(lesser) != orig_len - 1:
return pivot
else:
return findDuplicate(lesser) or findDuplicate(greater)
我认为它在O(n logn)中找到了重复。它使用堆栈上的额外内存,但我可以重写它只使用原始数据的一个副本,我相信:
def findDuplicate(arr):
orig_len = len(arr)
if orig_len <= 1:
return None
pivot = arr.pop(0)
greater = [arr.pop(i) for i in reversed(range(len(arr))) if arr[i] > pivot]
lesser = [arr.pop(i) for i in reversed(range(len(arr))) if arr[i] < pivot]
if len(arr):
return pivot
else:
return findDuplicate(lesser) or findDuplicate(greater)
产生更大和较小的列表推导通过调用pop()来破坏原始文件。如果 arr 在从中删除更大和 less 后不为空,则必须有重复且必须为 pivot
代码在排序数据上遇到通常的堆栈溢出问题,因此需要随机数据透视或对数据进行排队的迭代解决方案:
def findDuplicate(full):
import copy
q = [full]
while len(q):
arr = copy.copy(q.pop(0))
orig_len = len(arr)
if orig_len > 1:
pivot = arr.pop(0)
greater = [arr.pop(i) for i in reversed(range(len(arr))) if arr[i] > pivot]
lesser = [arr.pop(i) for i in reversed(range(len(arr))) if arr[i] < pivot]
if len(arr):
return pivot
else:
q.append(greater)
q.append(lesser)
return None
但是,现在代码需要在循环顶部获取数据的深层副本,从而改变内存需求。
对计算机科学来说太过分了。天真算法在python中破坏了我的代码,可能是因为python的排序算法:
def findDuplicate(arr):
arr = sorted(arr)
prev = arr.pop(0)
for element in arr:
if element == prev:
return prev
else:
prev = element
return None
答案 3 :(得分:2)
我建议编写一个比较排序函数的实现,它会在找到dup后立即退出,导致没有额外的内存需求(取决于您选择的算法,显然),而不是对数组进行排序然后进行检查。最糟糕的情况是O(nlogn)时间(再次,取决于算法),而不是最佳(和平均,取决于...)情况O(nlogn)时间。
E.g。就地合并排序的实现。
答案 4 :(得分:2)
提示:使用A XOR A == 0和0 XOR A == A的属性。
答案 5 :(得分:0)
作为解决方案的变体(2),您可以使用radix sort。没有额外的记忆,并将运行 线性时间。您可以争辩说时间也受到数字表示的大小的影响,但您已经为此给出了界限:基数排序在时间O(k n)中运行,其中k是您可以对每次通过排序的位数。这使得整个算法O(7n)用于排序加上O(n)来检查重复的数字 - 即O(8n)= O(n)。
优点:
缺点:
答案 6 :(得分:0)
找到所有重复的问题怎么样?这可以用不到的时间来完成 O(n nn)时间? (排序和扫描)(如果要恢复原始数组,请携带原始索引并在结束后重新排序,这可以在O(n)时间内完成)
答案 7 :(得分:0)
def singleton(array):
return reduce(lambda x,y:x^y, array)
答案 8 :(得分:0)
通过对它们应该放置的位置进行排序来对整数进行排序。如果你得到“碰撞”而不是找到正确的数字。
空间复杂度O(1)(可以覆盖的空间相同) 时间复杂度小于O(n)因为你会在结束前统计发现collison。