给出大小为n的整数数组。它只能包含0到n-2范围内的值。数组中可能有多个重复项。有没有办法在不修改数组的情况下确定O(n)时间和O(1)空间中所有可能的重复项?
答案 0 :(得分:0)
如果数组中的数字是任意的,我认为没有任何方式在O(n 2 )之内完成。
但是,我会仔细查看数据的限制,必须从0
到n-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
,因此我们可以完全跳过7
,4
和5
。当然,出于同样的原因,我们会跳过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代码: - )