确定大小为n的数组中的所有重复项,其中O(1)空间和O(n)时间内的值范围为0到n-2

时间:2015-02-04 16:22:28

标签: arrays algorithm duplicates

给出大小为n的整数数组。它只能包含0到n-2范围内的值。数组中可能有多个重复项。有没有办法在不修改数组的情况下确定O(n)时间和O(1)空间中所有可能的重复项?

有算法here,但会修改数组。还有另一种算法here,但从我可以看到它只能确定其中一个重复。有没有办法确定所有重复项?

1 个答案:

答案 0 :(得分:0)

如果数组中的数字是任意的,我认为没有任何方式在O(n 2 )之内完成。

但是,我会仔细查看数据的限制,必须从0n-2绘制可能的值。这允许你引入一个效率,虽然我认为不会让你从O(n 2 )回到O(n),但至少会大大改善运行时间你的算法。

这是它的工作原理。考虑从0..9范围中抽取的十个数字:

0 1 2 3 4 5 6 7 8 9

现在介绍一个副本:

0 1 2 3 4 5 6 2 8 9

你应该注意的一件事是,重复的引入在所使用的数字集中打开了一个漏洞 - 列表中不再有7

事实上,对于您引入的每个重复项,可能的值完全消失,您可以使用该事实来优化算法。这里的技巧是不在列表中搜索<​​em>每个可能的数字,而是使用每个搜索来找出你应该寻找的 next 号码(最低的数字是大于当前的数字)。考虑13个元素的列表:

{0, 1, 1, 1, 2, 3, 0, 7, 9, 3, 9, 3, 9}

首先,我们搜索0。我们发现它是重复的,但我们发现下一个可能的数字是1,所以我们记住下一阶段。

我们搜索1(重复),接下来是2,然后搜索2(唯一),接下来是{{1 }}

但在这里它变得有趣。当我们搜索3(重复)时,我们发现下一个可能的数字实际上是3,因此我们可以完全跳过745。当然,出于同样的原因,我们会跳过6(在搜索8时,我们发现下一个是7)。

当我们搜索9时,没有下一个可能的术语,因此我们可以在此时停止。

在伪代码 1 中,这将是:

9

如果您想要更高的性能,还有另一种可能的优化。目前,您在每次迭代时检查列表中的每个值,但这不是必需的。

例如,一旦你检查了list = [0,1,1,1,2,3,0,7,9,3,9,3,9] n = len(list) # Initial search term and begin loop for each term. currN = 0 while currN <= n - 2: print ("Checking for %d"%(currN)) # Next search term, initially beyond max, and dupe detector. nextN = n count = 0 # Check every list value. for val in list: # Count occurrences. if val == currN: count += 1 # Update next search term if needed. If no value # between curr and n, nextN will remain at n # and loop will exit. if val > currN and val < nextN: nextN = val # Inform if duplicated and move to next search term. if count > 1: print ("%d is duplicated"%(currN)) currN = nextN ,就没有必要再次检查第一个索引0,因为它永远不会再对结果产生影响。

同样,一旦您检查了{0},就无需再次重新访问前四个元素1

因此,不仅要记住下一个可能的搜索词,而且还要记住可以找到它的最早点,以便以后的迭代在搜索中处理更少的元素。

可行的方法是从最初位于列表开头的变量点搜索。但是,在每次传递时,您都会将此位置更新为列表中的第一个项,该项大于您当前正在处理的搜索项。

如上所述,我不相信这些建议中的任何一个会给你O(n),但它肯定比天真的方法更好。对于没有重复的情况(例如{0, 1, 1, 1}),直到大约n * n个操作,其中列表中只有一个重复值,操作范围从接近{1, 2, 3, 4}的操作开始(例如,n)。

重复次数越多,运行时间就越好。

1 ...看起来很像Python3代码: - )