降低列表操作的复杂性

时间:2015-11-25 07:56:16

标签: 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 − 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)的复杂性,我实际上并不知道这个例子是否属实。

5 个答案:

答案 0 :(得分:5)

实现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

答案 1 :(得分:2)

您可以通过一次从右和到左移一个值来递增计算总和。

以下是我的编写方式,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])

答案 2 :(得分:2)

您无需对所有元素进行求和。创建总和一次并在循环中更新它:

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

所以你从013开始,然后在循环中,当你将3的值从一个移到10时,它变为isum()总结到另一个。

您的解决方案是O(N * N),因为{{1}}函数循环。因此,对于列表推导中的每次迭代,当您将所有N个元素合计为两个总计时,您需要N个步骤,并且您有N个这样的迭代。

答案 3 :(得分:0)

L = [3, 1, 2, 4, 3]
sec_part = sum(L)
diff = []
for i in L:
    diff.append(abs(sec_part - i * 2))
    sec_part -= i * 2
print min(diff)
首先,总结整个列表,复杂度为O(N)

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

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

答案 4 :(得分:0)

我知道这里有太多解决方案。只是想在时间和空间上最容易添加算法。

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