【问题标题】:Extracting the subsequence of maximum length from a sequence [PYTHON] [duplicate]从序列中提取最大长度的子序列[PYTHON] [重复]
【发布时间】:2016-11-18 00:57:27
【问题描述】:

我有一个值序列 [1,2,3,4,1,5,1,6,7],我必须找到长度增加的最长子序列。但是,一旦达到比前一个低的数字,该函数就需要停止计数。在这种情况下,此序列中的答案是 [1,2,3,4]。因为它在重置之前有 4 个值。我将如何为此编写 Python 代码?

注意:找到“最长递增子序列”似乎是一个常见的挑战,因此在网上搜索我发现了很多解决方案,这些解决方案可以计算整个序列的长度,并返回一个递增值的子序列,而忽略任何递减,所以在这种情况下,它将返回 [1,2,3,4,5,6,7]。那不是我要找的。

它需要对每个子序列进行计数,并在达到低于前一个数字时重置计数。然后它需要比较所有计数的子序列,并返回最长的一个。

提前致谢。

【问题讨论】:

  • 这在算法方面似乎很简单,你试过解决吗? StackOverflow 不是代码编写服务。
  • 输入应返回的内容:[1,2,3,9,2,3,4,5,3,0,1,2,3,4,5,6]
  • 正如向我描述的那样,算法将存储每个子序列的长度,因此 1,2,3,9 是 4 个值,2,3,4,5 是 4,3 是 1 个值, 而 0,1,2,3,4,5,6 是 6 个值,因此它只会返回最终的最长子序列。
  • 这不是标记问题的重复,这实际上是一个简单得多的问题,根本无法通过“重复”解决

标签: python list python-3.x subsequence


【解决方案1】:

考虑一个生成所有可能的升序子序列的函数,您将从一个空列表开始,添加项目直到一个元素小于(或等于?)上一个元素,此时您保存(yield)子序列和重新开始一个新的子序列。

使用生成器的一个实现可能是这样的:

def all_ascending_subsequences(sequence):
    #use an iterator so we can pull out the first element without slicing
    seq = iter(sequence)

    try: #NOTE 1
        last = next(seq)  # grab the first element from the sequence
    except StopIteration: # or if there are none just return
        #yield [] #NOTE 2
        return

    sub = [last]
    for value in seq:
        if value > last: #or check if their difference is exactly 1 etc.
            sub.append(value)
        else: #end of the subsequence, yield it and reset sub
            yield sub
            sub = [value]
        last = value

    #after the loop we send the final subsequence
    yield sub

关于处理空序列的两个注意事项:

  1. 要完成一个生成器,StopIteration 需要 提出,所以我们可以让来自next(seq) 的人传播出去 - 但是当from __future__ import generator_stop 进来时 效果它会导致RuntimeError 所以为了将来兼容我们 需要抓住它并明确地return
  2. 正如我写的那样,将一个空列表传递给 all_ascending_subsequences 不会生成任何值,这可能不会 成为期望的行为。随意取消注释yield [] 到 传递空列表时生成一个空列表。

然后你可以通过在结果上调用max 来获得最长的key=len

b =  [1,2,3,4,1,5,1,6,7]

result = max(all_ascending_subsequences(b),key=len)
print("longest is", result)

#print(*all_ascending_subsequences(b))

【讨论】:

  • 感谢您,您以一种我可以真正理解的方式描述了它,这对我有很大帮助,因为如果我不这样做,我永远不会习惯于使用东西知道我在说什么。
  • 我很高兴这对您有所帮助,但是您提出问题的方式确实适合“这是执行此操作的代码”类型的解决方案-您更有可能获得(更多)如果您已经展示了您尝试过的内容或具体地谈到了您遇到的问题,那么像我这样的有用的解释性答案(很快)。
【解决方案2】:
b = [4,1,6,3,4,5,6,7,3,9,1,0]

def findsub(a):
  start = -1
  count = 0
  cur = a[0]
  for i, n in enumerate(a):
    if n is cur+1:
      if start is -1:
        start = i - 2
        count=1
      count+=1
      cur = n
    if n < cur and count > 1:
      return [a[j] for j in range(start,start+count+1)]


print findsub(b)

有点草率的算法,但我相信它可以满足您的需求。通常我不会简单地向您展示代码,但我怀疑这就是您想要的,我希望您可以从中学习,并根据您所学的内容创建自己的代码。

一种更好看的方式,因为我不喜欢这样:

b = [1,2,0,1,2,3,4,5]

def findsub(a):
  answer = [a[0]]
  for i in a[1:]:
    if answer[-1] + 1 is i:
      answer.append(i)
    if not len(answer) > 1:
      answer = [i]
    elif i < answer[-1] and len(answer) > 1:
      return answer
  return answer



print findsub(b)

【讨论】:

  • 我认为这会找到第一个有效的子序列,而不是最长的。试试[1,2,0,1,2,3,4,5]
  • @TadhgMcDonald-Jensen 我们必须在第一次新值小于当前值时停止。
  • 谢谢你,nephi12!它以我需要的方式工作,因为一旦达到低于前一个的数字,它就会停止计数。我需要它返回 longest 子序列,但不一定是第一个。由于我实际上正在尝试从中学习,您能否给我一个提示,告诉我我需要改变什么才能做到这一点,我会自己弄清楚吗?
  • 它应该如何在结束前停止并找到最长的?不知道我明白。
【解决方案3】:

您需要执行以下操作:

  1. 创建一个函数W,给定一个列表,返回最后一项的索引,该索引不是从列表开始严格递增的。

    • 例如,给定以下列表:[1,2,3,4,1,2,3], [4,2,1], [5,6,7,8],它应该为每个列表分别返回414
  2. 创建变量maxim并将值设置为0

  3. 重复执行以下操作,直到您的列表为空
    • 在你的列表中调用你的函数W,让我们调用返回值x
    • 如果x 大于maxim
      • maxim 设置为x
      • 此时,如果您希望存储此序列,可以使用list-slice notation 获取列表中包含该序列的部分。
    • 从列表中删除列表中的该部分

最后,打印maxim,如果您要存储列表中包含最长序列的部分,则打印您得到的最后一个

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 2012-09-07
    • 2016-06-03
    • 2021-12-29
    • 1970-01-01
    • 2020-04-14
    • 1970-01-01
    相关资源
    最近更新 更多