Python 降低列表操作的复杂性
我有一个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 −
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