【问题标题】:From set and dictionary, which is more efficient to find the first duplicate in a list?从集合和字典中,哪个更有效地找到列表中的第一个重复项?
【发布时间】:2022-01-07 14:57:55
【问题描述】:

我必须找到列表中的第一个重复元素。假设我有一个列表[1, 2, 3, 4, 3, 1, 2, 9]。这里的第一个副本是3,因为当我们从从左到右遍历它时,2nd 32nd 1之前排在第一位strong> 和 2

为了解决这个问题,我有两个解决方案。

使用集合

def firstDuplicateValue(array):
    duplicate = set()
    for value in array:
        if value in duplicate:
            return value
        else:
            duplicate.add(value)
    return -1

使用字典

def firstDuplicateValue(array):
    duplicate = {}
    for value in array:
        if value in duplicate:
            return value
        else:
            duplicate[value] = True
    return -1

在 python 中哪个更省时,为什么?还有其他最好的解决方案吗?

【问题讨论】:

  • @mama 字典不是无序的。他们的顺序在这里并不重要。
  • @rv.kvetch 显然,至少他们会这样做(我也是)。虽然我想看看你的Counter 解决方案(诚然只是指出这是错误的:-P)。
  • 字典用于存储键:值对,这里不需要,所以在这种情况下,设置解决方案似乎更可取
  • 请注意,in 对 set 和 dict 的测试都是常数时间 O(1),但是如果您只对键感兴趣,为什么要存储一个值呢?
  • @rv.kvetch 哈...我终于找到了可能稍微快一点的东西,它涉及...一个计数器:-)(但可能不在你想到的方式,我仍然怀疑它不能正常工作)

标签: python dictionary data-structures set


【解决方案1】:

在可以在 cmets 中找到的讨论中,有人正确地指出,上述方法的时间和内存效率会随着要查找的数组的大小而变化。

Set 和 Dictionary 都使用一组唯一键,因此具有相似的逻辑,查找这些键应该具有 O(n) 复杂度,并且它们不应该采用显着不同的 timex。下面的代码使用整数列表 0, 1, 2, ... 和末尾的另一个 0 来测试这些。另外,请注意,在下面的 cmets 中,有些人建议了其他(也许更好)方法来为过程计时。

import time
import sys

def firstDuplicateValueSet(array):
    duplicate = set()
    for value in array:
        if value in duplicate:
            print(sys.getsizeof(duplicate)/1024)
            return value
        else:
            duplicate.add(value)
    return -1

def firstDuplicateValueDict(array):
    duplicate = {}
    for value in array:
        if value in duplicate:
            print(sys.getsizeof(duplicate)/1024)
            return value
        else:
            duplicate[value] = True
    return -1

size = 50000000
arr = [i for i in range(size)]
arr.append(0)

tic = time.time()
firstDuplicateValueSet(arr)
toc = time.time()
print(toc-tic)
tic = time.time()
firstDuplicateValueDict(arr)
toc = time.time()
print(toc-tic)
tic = time.time()

firstDuplicateValueSet()的内存和时间:

>>> 2097152.21875
>>> 8.740191221237183

firstDuplicateValueDict()的内存和时间:

>>> 2621440.1015625
>>> 9.246715545654297

size 设置为81000000 会产生相反的结果。字典时间更短,Set 内存更多!

>>> 4194304.21875 #set memory
>>> 15.37313985824585 #set time
>>> 2621440.1015625 #dictionary memory
>>> 11.566540002822876 #dictionary time

【讨论】:

  • @PeptideWitch 最好还是 timeit 模块
  • 我尝试了大小 2650000 而不是你巨大的 1000000000,设置大小报告为 131072,而 dict 大小报告为 81920。此外,我多次运行它,dict 始终明显更快。所以你的两个说法似乎都是错误的。
  • 感谢您的批评顺便说一句,只是想提供帮助。我从来没有说过这是一个清单。我使用了一个数组,两个函数都以相同的方式读取数组。
  • 是的,5000 万,set 似乎更好,而 8100 万,dict 似乎更好。在更大的尺寸下,set 可能会再次变得更好,而在更大的尺寸下,它将再次成为 dict。等等。就像我说的,它们是跳跃式的,这取决于确切的大小。虽然我猜一个比另一个“平均”好,但我认为哪一个(或者如何首先定义“平均”:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多