如何通过替换python中的循环来减少算法中的执行时间

时间:2018-11-18 08:48:49

标签: python algorithm execution-time

我正在尝试解决算法问题,请考虑以下列表:

l =  [100, 20, 50, 70, 45]

在这个问题中,我必须找到直到索引i的元素的平均值:

i = 0
100
i = 1
(100 + 20) //2 = 60
i = 2
(100+20+50) // 3 = 56
...

最终结果应存储在列表中:

[100, 60, 56, 60, 57]

这是到目前为止的代码:

from functools import reduce
def meanScores(l):
      def av(x):
            return reduce(lambda a, b: a+b,x)//len(x)

      return [av(l[:i]) for i in range(1,len(l)+1)] 

效果很好,问题是提交时遇到了时间限制。我认为问题是for循环,因为len(l)超过一万时会花费很多时间。以前,我使用sum()进行平均,但是也花费了很多时间,当我将sum()转换为reduce(lambda a, b: a+b,x)//len(x)时,算法变得更快了(它解决了更多的测试用例)。如果不是使用for循环,而是使用另一个函数(例如lambda),则问题得以解决。那么您认为有办法吗?谢谢您的时间。

6 个答案:

答案 0 :(得分:3)

这是因为每次都对整个数组求和,所以成本是二次的,但是如果每次都重复使用以前的结果,则成本可能是线性的。考虑一下。

答案 1 :(得分:2)

您可以尝试使用numpy.cumsum并获得平均值除以汇总列表的index + 1。

import numpy as np

l =  [100, 20, 50, 70, 45]

l_cumsum = np.cumsum(l)
l_indices = np.arange(1,len(l)+1,1)
l_average = np.divide(l_cumsum, l_indices).tolist()

print(l_average) # Outputs [100.0, 60.0, 56.666666666666664, 60.0, 57.0]

应该很快,O(n),因为numpy.cumsum已经非常优化。如果仍然希望更快,则可以对其进行多线程处理。

答案 2 :(得分:1)

您想要做的就是在列表中仅迭代一次:

i = [10,20,30,40,50,60,70]


def meanScores(l):
    if len(l) == 0: #Check is its an empty list
        return []
    res = [l[0]] #the first item is the first item in both lists(l)):
        res.append(float((res[i-1]*i + l[i])) / (i+1)) #Use the previous result to calculate the new result
    return [int(x) for x in res]

对于使用先前的结果,我采用先前的总和(即上一个平均值* i),将新的数字相加,然后除以i + 1。

答案 3 :(得分:1)

一些想法:

  1. 每次运行av函数时,都会减少整个列表。自从您在列表理解中调用av以来,您拨打av的次数比您需要的次数多。您应该只计算一次汇总列表(使用av),并在遍历l时得出汇总。
  2. 由于您只汇总了i,因此不应减少整个列表。您应该先切片第一个列表l[:i],然后对缩短的列表运行reduce()

答案 4 :(得分:1)

由于完整的解决方案已经破坏了游戏,因此O(n)中的方法可行。

请注意,您通常可以避免自己在Python中操纵索引。在这里,我们可以使用enumerate(起始值为1)来跟踪求和的值的数量。

def means(lst):
    sum = 0
    out = []
    for n, new_val in enumerate(lst, 1): # we enumerate starting with n=1
        sum += new_val
        out.append(sum/n)
    return out

一些测试:

lst =  [100, 20, 50, 70, 45]
print(means(lst))
# [100.0, 60.0, 56.666666666666664, 60.0, 57.0]

print(means([]))
# []

答案 5 :(得分:1)

可以用线性时间复杂度即O(n)来实现。下面的示例只是为了给您一个想法,您将如何做。

l =  [100, 20, 50, 70, 45]

a = [0] * len(l)

a[0] = l[0]

temp = a[0]

for i in range(1, len(l)):
    a[i] = (temp + l[i]) / (i + 1)
    temp = temp + l[i]

print(a)
Output
[100, 60.0, 56.666666666666664, 60.0, 57.0]