检查列表中连续元素的不定和是否为给定值的Python方法

检查列表中连续元素的不定和是否为给定值的Python方法,python,list,Python,List,想不出一个好办法来完成这项任务 假设我有一个多达1000->[0,1,3,6,10,15]的三角形数字列表 给定一个数字,我想返回该列表中与该数字相加的连续元素 i、 e 64 --> [15,21,28] 225 --> [105,120] 371 --> [36, 45, 55, 66, 78, 91] 如果没有连续的数字相加,则返回一个空列表 882 --> [ ] 注意,在上述示例中,连续元素的长度可以是任意数字-3,2,6 蛮力方法将迭代检查每个元素的每个

想不出一个好办法来完成这项任务

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

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

i、 e

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]
def findConsec(输入1=7735): 列表1=范围(11001) newlist=[reduce(lambda x,y:x+y,list1[0:i])表示列表1中的i] curr=0 结束=2 num=sum(新列表[当前:结束]) 而num!=输入1: 如果numinput1: num-=newlist[curr] 电流+=1 如果curr==结束: 返回[] 如果num==input1: 返回新列表[当前:结束]
您应该选择前三个元素,将它们相加,然后继续减去三个元素中的第一个元素,并将下一个元素添加到列表中,然后查看总和是否达到您想要的数字。那就是O(n)


这似乎是一个算法问题,而不是如何在python中实现的问题

回想起来,我会复制这个列表,并以类似于埃拉托斯坦筛的方式使用它。我不会考虑大于X的数字。然后从最大数开始,向后求和。然后,如果我得到大于x的值,减去最大的数(从解中排除),然后继续向后求和。 对我来说,这似乎是最有效的方法,实际上是O(n)-你永远不会返回(或在这个反向算法中前进),除非你减去或删除最大的元素,它不需要再次访问列表-只是一个临时变量

要回答沙丘问题:

是的,这是有原因的——如果没有求和更大的解,就减去下一个最大值。从第一个元素开始,点击“无解决方案”将需要再次访问列表或临时解决方案列表,以减去一组总和大于下一个要求和的元素。访问更多元素可能会增加复杂性


为了在最终解决方案位于序列开头的情况下提高效率,可以使用二进制搜索搜索较小和较大的对。一旦找到一对小于x的2个元素,就可以求和,如果它的和大于x,就向左走,否则就向右走。这种搜索在理论上具有对数复杂性。实际上,复杂性不是理论上的复杂性,你可以做任何你想做的事情:)

一个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])

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

#对于Python2,将'highest=next(high)`替换为'highest=high.next()`
从itertools导入计数,takewhile,累加
def查找(要查找):
#下一个(低)=总数中的最低数量
#下一个(高)=未总计的最高数字
低=累加(计数(1))#三角形数生成器
高=累积(计数(1))
总计=最高=下一个(高)
#highest=序列中与总数相加的最大数
#如果总和中的最大值大于to_find,则肯定无法找到解决方案

你的问题是关于算法而不是它的实现?您希望它是pythonic或改进
O(n^2)
?对于两个答案:寻找两者。这里有一个是O(2^n),它不是更好,但可以看一些东西您不需要切片,可以使用一个简单的公式来计算连续数字的总和,但在这种情况下,与目标值相加的元素的#并不总是3。可能是1,2,3,10,等等,比O(n)差一点;如果您知道长度,这是一个很好的解决方案,但是如果您不知道,您必须尝试k次,直到第一个k的总和大于您要查找的总和。比原始问题中的暴力方法要好
# 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)
# 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 []