最快的方式返回列表中的重复元素,还找到列表中缺少的元素?

时间:2015-07-20 18:59:55

标签: python algorithm performance list

所以我的代码如下所示。输入是一个列表,其中只有一个重复项和一个缺失项。答案是两个元素的列表,其中第一个是列表中的重复元素,第二个是列表中缺少的元素,范围是1到n。 示例= [1,4,2,5,1]答案= [1,3] 以下代码有效。

是的,我错误地认为复杂性是O(n)并且有没有更快的方法在Python中实现这一点? 另外,有没有办法,我可以做到这一点,而无需使用额外的空间。

注意:元素的大小可以是10 ^ 5或更大

    n = max(A)
    answer = []
    seen = set()
    for i in A:
        if i in seen:
            answer.append(i)
        else:
            seen.add(i)

    for i in xrange(1,n):
        if i not in A:
            answer.append(i)
    print ans

2 个答案:

答案 0 :(得分:1)

你确实是正确的,这个算法的复杂性是O(n),这是你能达到的最好。完成重复值后,您可以尝试通过中止搜索来优化它。但最坏的情况是你的副本位于列表的后面,你仍然需要完全遍历它。

使用散列(使用一组)是一个很好的解决方案。还有很多其他方法,例如使用Counters。但这不会改变算法的渐近复杂性。

作为@Emisor建议,您可以利用您拥有1个重复值和1个缺失值的列表的信息。您可能知道如果您的列表没有重复且没有缺失值,那么总结列表中的所有元素将导致1+2+3+..+n,这可以在数学等价物(n*n+1)/2

当您发现重复值时,您可以计算缺失值,而无需执行:

for i in xrange(1,n):
    if i not in A:
        answer.append(i)

由于您知道所有值都存在的总和:total = (n*n+1)/2) = 15,并且您知道哪个值是重复的。通过获取A = [1,4,2,5,1]数组的总和13并删除重复的值1,结果为12

获取计算出的总数并从中减去计算出的12会得到3

这一切都可以写成一行:

(((len(A)+1)*(len(A)+2))/2)-sum(A)-duplicate

答案 1 :(得分:0)

轻微优化(我认为)

def lalala2(A):
    _max = 0
    _sum = 0
    seen = set()
    duplicate = None
    for i in A:
        _sum += i
        if _max < i:
            _max = i
        if i in seen:
            duplicate = i
        elif duplicate is None:
            seen.add(i)

    missing = -_sum + duplicate + (_max*(_max + 1)/2) # This last term means the sum of every number from 1 to N 
    return [duplicate , missing]

看起来有点丑陋,我自己做了sum()和max()之类的东西而不是依靠Python的工具。但是通过这种方式,我们只检查每个元素一次。此外,一旦发现副本,它就会停止向集合中添加内容,因为一旦知道最大值,它就可以从中计算缺少的元素