【问题标题】:Python list cumulative sum greater than rest of elements in listPython列表累积总和大于列表中的其余元素
【发布时间】:2019-11-13 09:42:48
【问题描述】:

我想编写一个函数,它将返回 cumsum 大于列表其余部分的最小数字。 List 将只有值 -1 和 1。列表可能有数百万个元素。 例如

v = [1 1 -1 1 -1 1 -1 1]

这里的答案应该是2,因为

1) 1 > 1 is False 
2) (1 + 1) 2 > 0 (-1 + 1 -1 +1 -1 +1)

再举一个例子

v = [-1 -1 1 1]

回答 4

我已经尝试过的代码:

def cumsum_grt(v):
    for i in range(1, len(v)):
        k = i
        if sum(v[:k]) > sum(v[k:]):
            break
    return k

这个功能很好用,但是有什么方法可以提高性能吗?由于无法在几秒钟内计算出大型列表的结果,因此失败。

【问题讨论】:

  • 您可能应该以 cumulative 的方式计算累积总和。
  • 不回答问题,但不需要k。在python 中,i 的值在循环结束后继续存在,因此您可以在使用k 的任何地方使用i
  • 为什么我的问题被标记为否定?
  • @BhaveshGhodasara [-1, -1, -1, -1] 的预期结果是什么?我编写的代码将返回1,因为0 大于-4
  • @RomanPerekhrest appologies,我错过了......是的答案应该是 1。

标签: python algorithm list


【解决方案1】:
def cumsum_grt(v):
    total_sum = sum(v)
    curr_sum = v[0]
    for i in range(1, len(v)):
        if curr_sum > (total_sum - abs(curr_sum)):
            break
        curr_sum += v[i]
    return i

测试:

lst = [1, 1, -1, 1, -1, 1, -1, 1]
lst2 = [1, 1, -1, 20, -1, 15, -1, 1]
lst3 = [-2, -1, 4, -1]
lst4 = [-1,-1,-1,-1]

print(cumsum_grt(lst))   # 2
print(cumsum_grt(lst2))  # 4
print(cumsum_grt(lst3))  # 3
print(cumsum_grt(lst4))  # 1

时间绩效测量:

In [101]: lst = [1, 1, -1, 20, -1, 15, -1, 5, -1, -2, 40]                                                                    

In [102]: %timeit cumsum_grt(lst)                                                                                            
70.3 µs ± 175 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [103]: %timeit cumsum_grt_lenik(lst)                                                                                      
8.23 µs ± 27.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [104]: %timeit cumsum_grt_roman(lst)                                                                                      
8.22 µs ± 30.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

【讨论】:

  • 你不需要从total_sum 中减去一些东西吗?
  • v = list(np.random.choice([-1,1], size=30000)) 我用这个列表进行了测试。用 lenik 的功能测试了你的功能。 Lenik 的函数耗时 2.99 毫秒,你的耗时 5.98 毫秒,而我的耗时 10.6 秒
  • @BhaveshGhodasara,我不同意你的时间安排,请查看我的互动会话时间更新
  • 我的方法并不比@lenik 的方法慢 2 倍。他们的时间很接近,他的方法可能会稍微快一些
  • плюс один за настойчивость и старания =)
【解决方案2】:

这是线性的,O(N),而你的版本是 O(N*N):

def cumsum_grt(v):
    so_far = 0
    the_rest = sum(v)
    for i in range(len(v)):
        if so_far > the_rest :
            return i
        so_far += v[i]
        the_rest -= v[i]
    return len(v)

【讨论】:

  • 我正在测试这个解决方案的时间。在测试这里给出的所有解决方案后,我会接受它的答案。
  • 这个函数不应该将输入[-1,-1,-1,-1]1 返回为“cumsum 大于列表其余部分的最小数字”。 ?第一个数字-1 大于剩余的-3。但它返回0
  • @lenik:非常感谢。我现在会尝试理解逻辑:)
  • @BhaveshGhodasara 逻辑非常简单,列表有两部分,开头和列表的其余部分。这和你做的差不多,除了,我不是每次都计算这些部分的总和,我只是添加/减去当前元素以保持它们更新,这让事情变得更快。
  • @lenik 是的,我明白了。我的问题现在听起来很愚蠢:)。
【解决方案3】:

您可以将nextitertools.accumulate 一起使用,将当前累计总和与总和减去累计总和进行比较,然后使用enumerate 获得该位置的索引。 chain[0] 表示列表第一个元素之前的位置。

>>> from itertools import accumulate, chain
>>> v = [1, 1, -1, 1, -1, 1, -1, 1]
>>> s = sum(v)
>>> next((i for i, a in enumerate(chain([0], accumulate(v))) if a > s - a), len(v))
2

注意:不要在if 条件内计算sum(v),否则它将是 O(n²)。末尾的len(v) 是默认值,以防累积总和不足以容纳任何元素。

【讨论】:

  • OP 说答案应该是2 ??
  • 我正在测试这个解决方案的时间。在测试这里给出的所有解决方案后,我会接受它的答案。
猜你喜欢
  • 1970-01-01
  • 2018-07-02
  • 1970-01-01
  • 2022-01-11
  • 2023-01-12
  • 1970-01-01
  • 2019-04-29
  • 2017-06-20
  • 2021-10-28
相关资源
最近更新 更多