Python程序,用于查找添加到键的子列表

Python程序,用于查找添加到键的子列表,python,Python,我被要求编写一个python函数来验证列表l(即一个连续的子列表)中是否至少有一个连续的正整数序列,该序列可以求和为给定的目标正整数t(键)并返回包含可在其中找到该序列的最小开始索引和结束索引的字典最小列表,或者在没有该序列的情况下返回数组[-1,-1]。例如,一个包含元素[4,3,5,7,8]和键t为12的列表l,函数将返回列表[0,2],因为该列表包含值4,3和5的索引,而另一个列表l包含元素[1,2,3,4]和键t为15,函数将返回[-1,-1]因为没有列表l的子列表可以求和到给定的目标值

我被要求编写一个python函数来验证列表l(即一个连续的子列表)中是否至少有一个连续的正整数序列,该序列可以求和为给定的目标正整数t(键)并返回包含可在其中找到该序列的最小开始索引和结束索引的字典最小列表,或者在没有该序列的情况下返回数组[-1,-1]。例如,一个包含元素[4,3,5,7,8]和键t为12的列表l,函数将返回列表[0,2],因为该列表包含值4,3和5的索引,而另一个列表l包含元素[1,2,3,4]和键t为15,函数将返回[-1,-1]因为没有列表l的子列表可以求和到给定的目标值t=15。我应该写一个函数来标识第一个给定的子列表,该子列表汇总到键t,因此它应该只返回一个子列表。子列表只能通过以下方式识别:

  • 每个列表l将包含至少1个元素,但不超过100个
  • l的每个元素将介于1和100之间
  • t为正整数,不超过250
  • 列表l的第一个元素的索引为0
  • 对于解决方案(l,t)返回的列表,开始索引必须等于或小于结束索引。 到目前为止,我已经能够实现前面提到的前两个示例。这就是我迄今为止所尝试的:
def溶液(l,t): 如果len(l)0和t>0和t
def find_seq(inp_列表,目标):
开始=结束=0
启动时目标:
开始+=1
如果开始>结束和结束<长度(输入列表):
结束+=1
elif值<目标:
如果结束<长度(输入列表):
结束+=1
其他:
返回[-1,-1]
其他:
返回[开始,结束]
返回[-1,-1]
查找顺序([4,3,5,7,8],12)#[0,2]
由于您关注的是正整数的连续子列表,因此可以简化问题

我们限制自己通过数字从左向右移动,即开始/结束只能递增,不能递减。这不应导致我们丢失任何解决方案,因为我们可以通过从所选子列表的开始处开始并递增其开始/结束处来访问任何可能的子列表,并在下面进一步解释其他原因

给定一个连续的子列表,您的值可能太大、太小或等于目标值。如果它等于目标,那么您就完成了

如果它太大,那么您需要删除一些数字。因为我们只是在向右转,所以删除数字的唯一方法是增加起始值。为了确保我们不跳过任何解决方案,我们以尽可能小的数量递增start,即1。我们不能让开始超出子列表的结尾,因此如果开始和结束彼此相等,我们必须同时递增。我们不能让结束超过输入列表的结束,所以我们只能在能够的情况下增加结束

另一方面,如果当前子列表和太小,则需要添加数字。这意味着我们需要增加end,这将给我们一个新的数字来包含在总和中。因为结束不能超过输入列表的结束,所以我们只有在能够的情况下才能增加。如果我们不能,那就意味着我们没有数字可加,我们的价值太小。这意味着我们永远不会达到该值,并且可以以(-1,-1)结果终止(没有匹配项添加到目标)

你可能会问,我们为什么不把起点向后移呢?如果我们这样做了,我们会有一个太大的值(甚至不包括输入列表中的最后一个数字),这必须是真的,我们的结束索引才能到达结束。请记住,只有当前一个和太大时,起始索引才会增加,因此在某些时候,我们会增加起始索引,因为该和太大。自从那项决定以来,我们已经向前推进,增加了更多的东西。因此,向后移动起始位置将导致子列表太大

最后,如果start曾经到达输入列表的末尾,那么我们已经检查了所有的可能性,但什么也没有发现


从性能的角度来看,您可以通过只跟踪一个求和值,并在每次递增结束时添加新值,在每次递增开始时减去旧的左值,从而使您不必在每次循环迭代中对整个开始到结束子列表求和。我没有费心这么做,但你可以。

这可以解决任务:

def summing_up_target(lst, t):
    for i in range(len(lst)):
        for ii in range(i,len(lst)):
            if sum(lst[i:ii]) == t:
                return [i,ii]
            elif sum(lst[i:ii]) > t:
                break
    return [-1, -1]

summing_up_target([4, 3, 5, 7, 8], 12)
说明:

  • 您可以通过将输入列表切片到子列表来迭代输入列表
  • 如果其中一个子列表与目标匹配,则返回
    True
    ,如果子列表的总和超出
    目标
    ,则移动到列表中的下一个索引并从那里继续切片

这是O(n^2),效率非常低。@Boris内部迭代没有覆盖整个n长度,首先是因为每次移动一步,并且有一个中断条件不超过target@IgnacioAlorre
求和目标([1,1,1,1,1,6])
将执行5^2/2次求和操作。实际上,它的作用更大。回想起来,我的代码出了什么问题?通过将子列表的总和保留在一个变量中,并减去移动
开始时留下的元素,或者在移动
结束时添加包含的元素,而不是调用
sum()来提高代码的效率
每次都是这样,但那样的话可读性就会降低。@Boris同意——事实上,我几分钟前在底部添加了同样的建议。不过,我的时区已经很晚了,我要去睡觉,而不是那样做。:)
def summing_up_target(lst, t):
    for i in range(len(lst)):
        for ii in range(i,len(lst)):
            if sum(lst[i:ii]) == t:
                return [i,ii]
            elif sum(lst[i:ii]) > t:
                break
    return [-1, -1]

summing_up_target([4, 3, 5, 7, 8], 12)