繁体   English   中英

Pythonic方法检查列表中的不连续元素数量是否达到给定值

[英]Pythonic way of checking if indefinite # of consec elements in list sum to given value

无法找到完成此任务的好方法。

假设我有一个最多1000的三角形数字列表 - > [0,1,3,6,10,15,..]等

给定一个数字,我想返回该列表中与该数字相加的连续元素。

64 --> [15,21,28]
225 --> [105,120]
371 --> [36, 45, 55, 66, 78, 91]

如果没有连续的数字加起来,则返回一个空列表。

882 --> [ ] 

请注意,连续元素的长度可以是任何数字 - 在上面的示例中为3,2,6。

蛮力方式将迭代地检查每个元素的每个可能的连续配对可能性。 (从0开始,查看[0,1]的总和,查看[0,1,3]之和等,直到总和大于目标数)。 但那可能是O(n * 2)或者可能更糟。 有什么方法可以做得更好吗?

更新:好的,所以我的一个朋友找到了一个在O(n)工作的解决方案(我认为)并且非常直观易于理解。 这可能与Gabriel的答案相似(或相同),但我很难跟上,我喜欢这个解决方案即使从基本的角度来看也是可以理解的。 这是一个有趣的问题,所以我将分享她的答案:

def findConsec(input1 = 7735):

    list1 = range(1, 1001)
    newlist = [reduce(lambda x,y: x+y,list1[0:i]) for i in list1]

    curr = 0
    end = 2
    num = sum(newlist[curr:end])

    while num != input1:

        if num < input1:
            num += newlist[end]
            end += 1

        elif num > input1:
            num -= newlist[curr]
            curr += 1

        if curr == end:
            return []

    if num == input1:
        return newlist[curr:end]

3次迭代最大解决方案另一种解决方案是从关闭位置开始,然后从后面的一个位置向前走。 对于三角形列表vec中的任何数字,它们的值可以通过它们的索引定义为:

vec[i] = sum(range(0,i+1))

查找总和值与组长度之间的区别是组的平均值,因此位于组内,但也可能不存在。 因此,您可以设置起始点,以查找一组n个数字,其总和与值val匹配,作为它们之间除法的整数部分。 因为它可能不在列表中,所以该位置将最小化它们的差异。

# vec as np.ndarray -> the triangular or whatever-type series
# val as int -> sum of n elements you are looking after
# n as int -> number of elements to be summed
import numpy as np

def seq_index(vec,n,val):
    index0 = np.argmin(abs(vec-(val/n)))-n/2-1 # covers odd and even n values
    intsum = 0 # sum of which to keep track
    count = 0 # counter
    seq = [] # indices of vec that sum up to val

    while count<=2: # walking forward from the initial guess of where the group begins or prior to it
        intsum = sum(vec[(index0+count):(index0+count+n)])
        if intsum == val:
            seq.append(range(index0+count,index0+count+n))
        count += 1
    return seq

# Example

vec = []

for i in range(0,100):
    vec.append(sum(range(0,i))) # build your triangular series from i = 0 (0) to i = 99 (whose sum equals 4950)

vec = np.array(vec) # convert to numpy to make it easier to query ranges

# looking for a value that belong to the interval 0-4590
indices = seq_index(vec,3,4)
# print indices
print indices[0]
print vec[indices]
print sum(vec[indices])

返回

print indices[0] -> [1, 2, 3]
print vec[indices] -> [0 1 3]
print sum(vec[indices]) -> 4 (which we were looking for)

这似乎是一个算法问题而不是如何在python中执行它的问题。

向后思考我会复制列表并以类似于Eratosthenes筛选的方式使用它。 我不会考虑大于x的数字。 然后从最大数字开始并向后总结。 然后,如果我得到大于x,减去最大数字(从解决方案中排除)并继续向后求和。 这对我来说似乎是最有效的方式,实际上是O(n) - 你永远不会回头(或者在这个后向算法中前进),除非你减去或删除最大的元素,不需要再次访问列表 - 只是温度变量

回答沙丘问题:

是的,有一个原因 - 在没有解决方案的情况下减去下一个最大值。 从第一个元素开始,点击无解决方案将需要再次访问列表或临时解决方案列表以减去一个总和大于下一个元素的元素集合。 您可能会通过访问更多元素来增加复杂性。

为了提高最终解决方案位于序列开头的情况下的效率,您可以使用二进制搜索来搜索越来越小的对。 一旦找到一对小于x的2个元素,那么你可以对该对进行求和,如果它总和大于x,则向左移动,否则你就向右移动。 该搜索在理论上具有对数复杂性。 在实践中复杂性不是理论上的,你可以做任何你喜欢的事情:)

你应该选择前三个元素,对它们求和,然后你继续减去三个元素中的第一个,然后在列表中添加下一个元素,看看总和是否加起来你想要的任何数字。 那将是O(n)。

# vec as np.ndarray

import numpy as np    

itsum = sum(list[0:2]) # the sum you want to iterate and check its value
sequence = [[] if itsum == whatever else [range(0,3)]] # indices of the list that add up to whatever (creation)
for i in range(3,len(vec)):
    itsum -= vec[i-3]
    itsum += vec[i]
    if itsum == whatever:
        sequence.append(range(i-2,i+1)) # list of sequences that add up to whatever

您在问题中提供的解决方案并非真正的O(n)时间复杂度 - 计算三角形数字的方式使得计算O(n 2 )。 列表理解抛弃了以前需要计算最后三角形数的工作。 即:tn i = tn i-1 + i(其中tn是三角形数)。 由于您也将三角形数字存储在列表中,因此空间复杂度不是恒定的,而是与您要查找的数字的大小相关。 下面是一个相同的算法,但是O(n)时间复杂度和O(1)空间复杂度(为python 3编写)。

# for python 2, replace things like `highest = next(high)` with `highest = high.next()`
from itertools import count, takewhile, accumulate

def find(to_find):
    # next(low) == lowest number in total
    # next(high) == highest number not in total
    low = accumulate(count(1)) # generator of triangle numbers
    high = accumulate(count(1))
    total = highest = next(high)
    # highest = highest number in the sequence that sums to total

    # definitely can't find solution if the highest number in the sum is greater than to_find
    while highest <= to_find:
        # found a solution
        if total == to_find:
            # keep taking numbers from the low iterator until we find the highest number in the sum
            return list(takewhile(lambda x: x <= highest, low))
        elif total < to_find:
            # add the next highest triangle number not in the sum
            highest = next(high)
            total += highest
        else: # if total > to_find
            # subtract the lowest triangle number in the sum
            total -= next(low)

    return []

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM