Python 算法优化-在列表中查找唯一编号

Python 算法优化-在列表中查找唯一编号,python,algorithm,list,optimization,Python,Algorithm,List,Optimization,目标是在一个数组中找到唯一的数字,该数组包含除一之外的相同数字。速度至关重要,因为阵列可能非常庞大。下面的代码适用于较小的阵列,但适用于较大的阵列。如何改进算法?请参见下面的输入/输出示例: 输入=[1,1,1,1,2,1,1,1,1,1] 输出=2 def find_uniq(arr): result = [x for x in arr if arr.count(x) ==1] return result[0] 使用NumPy: np.where(np.bincount(a

目标是在一个数组中找到唯一的数字,该数组包含除一之外的相同数字。速度至关重要,因为阵列可能非常庞大。下面的代码适用于较小的阵列,但适用于较大的阵列。如何改进算法?请参见下面的输入/输出示例:

输入=[1,1,1,1,2,1,1,1,1,1] 输出=2

def find_uniq(arr):

    result = [x for x in arr if arr.count(x) ==1]
    return result[0]
使用NumPy:

np.where(np.bincount(arr) == 1)
您当前的解决方案是二次型的

您可以使用
collections.Counter
并结合
next
(当您不希望构建整个列表时,这非常方便)。预计算计数,然后返回找到的第一个唯一值

from collections import Counter

def find_uniq(arr):
    c = Counter(arr)
    return next(x for x in arr if c[x] == 1)
下一步
在这里大放异彩,因为目标是返回找到的第一个唯一值<代码>下一步与生成器一起工作,只返回第一项(进一步的计算停止)

输出:

{1: 2, 2: 2, 3: 2, 4: 2, 5: 2, 6: 2, 7: 2, 8: 2, 9: 1}

现在根据您的情况检查字典中的键和值。

有时最愚蠢的解决方案并不是最糟糕的:

def find_uniq(arr):
    count = arr.count
    for x in arr:
        if count(x) == 1:
            return x
    return None

根据第一个唯一项的位置,这可能比Coldspeed的基于
计数器
的解决方案更快或更慢(该解决方案似乎最稳定)。在最坏的情况下,它只比OP的解决方案稍微快一点,但占用的内存更少。在最好的情况下,它显然是赢家;)

我认为这是最好的解决方案,因为当试图找到唯一的数字时,它迭代计数器字典,而不是原始数组(可能更长)。它将使用Python的整数或浮点数列表作为函数输入

from collections import Counter

def find_uniq(arr):
    return next(k for k,v in Counter(arr).items()
                if v == 1)
或者如果您可能有多个计数为1的数字:

from collections import Counter

def find_uniq(arr):
    return [k for k,v in Counter(arr).items()
            if v == 1]

这里有一个快速找到它的方法

def find_uniq(arr):

    members = list(set(arr))
    for member in members:
        if arr.count(member) == 1:
            return member
        continue
    return None #if there aren't any uniques
您已经找到了解决此问题的最快通用解决方案。对于任何已排序或未排序的数组,几乎是线性的

由于问题已标记,我想向您展示如何在不使用任何模块的情况下仍然以线性时间复杂度解决问题,只需使用算法:

def find_uniq(arr):
    i = 0
    while i < len(arr):
        j = i + 1
        pivot = arr[i] # store arr[i] so you don't have to access array again to read its value
        while j < len(arr) and pivot == arr[j]:
            j += 1
        if j - i == 1: # if previous loop never executed
            return pivot
        i = j
    return None
def find_uniq(arr):
i=0
而我
关于它的复杂性:这不仅仅是O(n),它也是Θ(n),因为
i=j
确保您不会多次访问任何数组元素。空间复杂度为O(1)


关于它的正确性:只有当输入数组被排序时,它才起作用!所以这里有个大问题。如果您可以构建已排序的数组,那么此算法将比
计数器
和其他任何算法都要快。问题是,如果数组尚未排序,则必须对其进行排序
arr.sort()
使用Timsort算法,即Ω(log(N!))、Θ(log(N!))和O(log(N!)),最坏情况下的空间复杂度为O(N)。因此,在最坏的情况下(数组尚未排序),整个代码将为O(log(N!))。但是仍然比O(n2)好。

在这个问题的任何地方都没有提到numpy,这也没有证明任何算法技术。不知道为什么这个答案会有一个向上投票。在快速基准测试(使用timeit和一个随机排列的列表,其中包含2个唯一值和200个重复值)之后,它始终是最慢的解决方案(比OP的解决方案慢)。注意:基于debian发行版的Python2.7.6。请提供一个预期输入和输出的示例(并改进标题!)似乎让很多人感到困惑。:)为未能提供示例而道歉。s/c[arr]/c[x]/actually;)@布鲁诺德修利耶哇,没看见那个家伙。别扭!谢谢。它将给出列表中的第一个唯一值,对吗?@bhansa
目标是在数组中找到唯一的数字
,因此我假设只有一个存在。如果存在更多,则只找到第一个。在任何情况下,函数都应该返回一个整数,而不需要进行不必要的计算。如果构建整个列表,并返回l[0],请考虑这样一种情况:您在开始时找到了唯一的元素,但最终不必要地遍历了整个列表。@bhansa Bitwise在非唯一元素出现奇数次时不是一个好主意。这不是“列表”理解,这是一个听写理解-显然。。。而且第一个
R\u dic=dict()
完全没有用处。
from collections import Counter

def find_uniq(arr):
    c = Counter(arr)
    return next(x for x in arr if c[x] == 1)
def find_uniq(arr):
    i = 0
    while i < len(arr):
        j = i + 1
        pivot = arr[i] # store arr[i] so you don't have to access array again to read its value
        while j < len(arr) and pivot == arr[j]:
            j += 1
        if j - i == 1: # if previous loop never executed
            return pivot
        i = j
    return None