Python 降低列表操作的复杂性

Python 降低列表操作的复杂性,python,list,time-complexity,Python,List,Time Complexity,我有一个python问题要解决,我确实解决了,但是我得到了一些关于解决方案糟糕性能的批评……因此我想在这里分享它,并检查可能的改进: 问题很简单,它是关于找到列表第一部分和第二部分之和之间的最小绝对差 例如,如果我们有: L = [3, 1, 2, 4, 3] 我们可以将其分为四个阶段: i = 1, abs difference = |3 − 10| = 7 i = 2, abs difference = |4 − 9| = 5 i = 3, abs difference = |6 −

我有一个python问题要解决,我确实解决了,但是我得到了一些关于解决方案糟糕性能的批评……因此我想在这里分享它,并检查可能的改进:

问题很简单,它是关于找到列表第一部分和第二部分之和之间的最小绝对差

例如,如果我们有:

L = [3, 1, 2, 4, 3]
我们可以将其分为四个阶段:

i = 1, abs difference = |3 − 10| = 7 
i = 2, abs difference = |4 − 9| = 5 
i = 3, abs difference = |6 − 7| = 1 
i = 4, abs difference = |10 − 3| = 7 
在此示例中,脚本应返回
1
作为最小绝对差

正如我所说,这对我来说很容易,我做到了:

def get_minAbsDiff(L):
    return min([abs(sum(L[0:i+1]) - sum(L[i+1:])) for i in xrange(len(L)-1)])
然而,这似乎是太时间复杂的解决方案O(N*N)

这个问题有可能得到O(N)吗

编辑:


是其他人告诉我这个O(N*N)复杂性,我实际上不知道这个例子是不是真的。

你可以通过从右和向左和一次移动一个值来增量计算和

下面是我如何编写它的,
sums
xs
的所有分区生成为左和右,并生成它们的和

def sums(xs):
    left, right = 0, sum(xs)
    for x in xs:
        yield left, right
        left += x
        right -= x
    yield left, right

def min_abs_diff(xs):
    return min(abs(left - right) for left, right in sums(xs))

print min_abs_diff([3, 1, 2, 4, 3])

你不必总是对所有元素求和。创建一次总和并在循环中更新:

def min_abs_diff(L):
    sum1, sum2 = 0, sum(L)
    min_abs_diff = float('inf')  # sentinel value
    for i in L:
        sum1 += i
        sum2 -= i
        abs_diff = abs(sum1 - sum2)
        if min_abs_diff > abs_diff:
            min_abs_diff = abs_diff
    return min_abs_diff
因此,您从
0
13
开始,然后在循环中,当您将
i
的值从一个和移到另一个时,这将变成
3
10

您的解决方案是O(N*N),因为
sum()
函数也会循环。因此,对于列表理解中的每个迭代,当你将所有N个元素相加为两个总数时,你需要N个步骤,并且你有N个这样的迭代。

实现O(N)解决方案的关键是要认识到,当你在列表中移动时,你从一个和中减去,然后加到另一个和中。所以

def get_minAbsDiff(L):
    leftSum = 0
    rightSum = sum(L)
    minDiff = rightSum

    for i in L:
        leftSum += i
        rightSum -= i
        diff = abs(leftSum-rightSum)

        if diff < minDiff: minDiff = diff

    return minDiff
def get_minAbsDiff(L):
leftSum=0
rightSum=总和(L)
minDiff=rightSum
对于L中的i:
leftSum+=i
右和-=i
差异=绝对值(左和右和)
如果diff
首先,总结整个列表,复杂性为O(N)

第二,使用for循环来减少值ps:我们应该减少item的两倍,因为我们在第一步添加它。for循环的时间复杂度也是O(N)


第三,使用
min
找出最小值,时间复杂度也是O(N)

我知道这里已经有太多的解决方案了。只是想在时间和空间上添加最简单的算法

testList = [1,2,3,4,5]

totalSum = sum(testList)

currentSum = 0
minDiff = totalSum

for a in testList:
    currentSum += a
    minDiff = min( abs(totalSum - currentSum - currentSum), minDiff)

print minDiff

是的,您生成的代码是O(N*N),因为
sum()
也在元素上循环。因此,对于
xrange()
循环中的每个
i
,您可以循环
L
中的所有元素,只循环求和。@马丁:好的,谢谢您的解释!因为所有的答案对我来说都很好,我必须选一个…我会选这个来解释O(N*N)!!
testList = [1,2,3,4,5]

totalSum = sum(testList)

currentSum = 0
minDiff = totalSum

for a in testList:
    currentSum += a
    minDiff = min( abs(totalSum - currentSum - currentSum), minDiff)

print minDiff