python 在数组中查找使用最少的元素时,代码战的执行超时,需要优化,但不知道如何优化

llew8vvj  于 2022-12-21  发布在  Python
关注(0)|答案(4)|浏览(101)

关于代码战的说明:
有一个包含一些数字的数组。除了一个数字之外,所有的数字都是相等的。试着找到它!
find_uniq([1,1,1,2,1,1])== 2 find_uniq([0,0,0.55,0,0])== 0.55保证数组至少包含3个数字。
测试包含一些非常大的数组,因此要考虑性能。
这是我写的代码:

def find_uniq(arr):
    for n in arr:
        if arr.count(n) == 1:
            return n
            exit()

其工作原理如下:对于数组中的每个字符,如果该字符只出现一次,则返回该字符并退出代码;如果该字符出现多次,则不执行任何操作在codewars上尝试代码时,我得到以下错误:
STDERR执行超时(12000毫秒)
我是一个初学者,所以我不知道如何进一步优化代码,以便它不超时
我的代码的第一个版本看起来像这样:

def find_uniq(arr):
    arr.sort()
    rep = str(arr)
    for character in arr:
        cantidad = arr.count(character)
        if cantidad > 1:
            rep = rep.replace(str(character), "")
    rep = rep.replace("[", "")
    rep = rep.replace("]", "")
    rep = rep.replace(",", "")
    rep = rep.replace(" ", "")
    rep = float(rep)
    n = rep
    return n

在超时之后,我认为这是由于重复的替换函数,以及代码必须遍历每个元素(即使已经找到正确的元素)的事实,因为代码删除了不正确的元素,而不仅仅是返回正确的元素
经过一些我没有保存的迭代之后,我们得到了当前代码,它检查字符是否在数组中只有一次,返回并退出

def find_uniq(arr):
    for n in arr:
        if arr.count(n) == 1:
            return n
            exit()

我不知道如何进一步优化它

f2uvfpb9

f2uvfpb91#

你可以使用dictcollections.Counter来得到每个元素的频率,其时间复杂度为线性,然后返回频率为1的元素。

def find_uniq(l):
    from collections import Counter
    return Counter(l).most_common()[-1][0]
zengzsys

zengzsys2#

每次调用.count()时,它都会遍历整个数组。如果您的数组包含n元素,它将遍历数组n次,这是相当慢的。
您可以按照Unmitigate的建议使用collections.Counter,但是如果您不熟悉该模块,那么对于这个问题来说,它似乎有些过头了,因为在本例中您知道数组中只有两个唯一元素,所以可以使用set()获得所有唯一元素,然后检查每个唯一元素的频率:

def find_uniq(arr):
    for n in set(arr):
        if arr.count(n) == 1:
            return n
wwtsj6pe

wwtsj6pe3#

比较前两个数字。如果它们匹配,则查找数组中不匹配的数字(最长解)。否则,返回与第三个数字不匹配的数字。编码为:

def find_uniq(arr):
    if arr[0]==arr[1]:
        target=arr[0]
        for i in range(2,len(arr)):
            if arr[i] != target:
                return arr[i]
    else:
        if arr[0]==arr[2]:
            return arr[1]
        else:
            return arr[0]
wqnecbli

wqnecbli4#

在原始代码中:

def find_uniq(arr):
    for n in arr:
        if arr.count(n) == 1:
            return n
            exit()  # note: this line does nothing because you already returned

对数组中的每个元素调用一次arr.count(假设最坏的情况是唯一元素在最末尾),每次调用arr.count(n)都会扫描整个数组,从n开始计数--所以要对整个N个元素的数组迭代N次,这就是O(N^2)--如果N很大的话会非常慢!
第二个版本的代码也有同样的问题,但是它将列表转换为字符串,然后尝试解析该字符串,从而增加了大量额外的复杂性--不要这样做!
加快速度的方法是迭代整个列表 * 一次 *,并跟踪每一项的计数,使用内置的collections.Counter类最容易做到这一点:

from collections import Counter

def find_uniq(arr):
    return next(i for i, c in Counter(arr).items() if c == 1)

如果数组中只有两个不同的值,并且其中一个值是唯一的,那么您可以通过将其分为两种可能性来提高效率(在所有情况下,您甚至不需要迭代整个数组):要么前两项是相同的,你只需要找到不等于它们的项,要么它们是不同的,你只需要返回不等于第三项的项.

def find_uniq(arr):
    if arr[0] == arr[1]:
        # First two items are the same, iterate through
        # the rest of the array to find the unique one.
        return next(i for i in arr if i != arr[0])
    # Otherwise, either arr[0] or arr[1] is unique.
    return arr[0] if arr[1] == arr[2] else arr[1]

在这种方法中,您只需要迭代数组中的唯一项(或者在它是前两个项之一的情况下正好超过它一个项).在唯一项接近一个非常长的数组的开始的特定情况下,这将比无论如何都迭代整个数组的方法快得多.在最坏的情况下,你仍然只有一次迭代。

相关问题