用列表中的重复项确定丢失的数字

时间:2018-07-14 14:14:41

标签: python algorithm time-complexity

我有一个列表l = [3,1,2,5,3]。我的目标是在 O(n)时间中找到重复编号,这里是3,而 missing 编号是4。最后,输出应为[3, 4]

我尝试使用字典查找重复的数字,但再次查找丢失的数字,我正在使用另一个循环,这导致 O(n ^ 2)时间复杂度。

任何人都可以说出如何在 O(n)时间复杂度中找到答案吗?

1 个答案:

答案 0 :(得分:3)

如果您嵌套 循环,则只会得到O(n ^ 2)解决方案。 O(n)的多个顺序循环(因此,在前一个循环完成后,下一个循环将运行)加在一起为O(n)最终解决方案,您可以根据需要使用任意多个循环。

如果您的输入不包含开始和结束数字,并且您只知道它们将是一个正整数序列,且其中一个数字中间某处缺失,那么解决方案是首先计算数字并记录最小和最大数字。然后从最小到最大循环,并包括任何缺少的数字或计数为2的数字。使用字典计数,这样您还将知道缺少的数字:

def missing_or_doubled(inputlist):
    counts = {}
    for n in inputlist:  # O(n) loop
        counts[n] = counts.get(n, 0) + 1
    start, end = min(counts), max(counts)  # two sequential O(n) loops
    # final O(n) loop to find missing number and number that appears twice
    return [i for i in range(start, end + 1) if counts.get(i) in {2, None}]

这是4个不同的O(n)循环,都按顺序进行。您也可以在start循环内确定endfor n in inputlist,但这会变得更慢。 min()max()函数是用C实现的,其不变成本较低,将胜过用纯Python实现的任何尝试。

演示:

>>> missing_or_doubled([3, 1, 2, 5, 3])
[3, 4]
>>> missing_or_doubled([14, 19, 17, 13, 12, 10, 16, 17, 18, 22, 11, 15, 20])
[17, 21]

如果您确实知道开头或结尾的号码(因为它是作为参数传递到代码中的,或者问题描述中明确指出了开头或结尾的号码是什么),则只需替换{{ 1}}或min(counts)分配信息。例如,如果起始编号始终应该为max(counts),则只需使用1