Python 递归以查找具有特定限制的最长递增子序列

Python Recursion to Find The Longest Increasing Subsequence with Specific Limitations

提问人:Saiko 提问时间:7/4/2023 最后编辑:Saiko 更新时间:7/4/2023 访问量:180

问:

我正在处理一个问题,我需要在 Python 中实现一个递归函数,以从数字列表中找到最长的递增子序列的长度。该列表可以具有任意长度,并且可以包含任何整数。我只允许使用函数和递归来解决这个问题,不允许使用循环、max()、辅助函数或任何其他内置函数。len()

问题描述如下:

给定一个数字列表,找到创建一系列严格递增的数字的最长子序列的长度。不得更改列表中数字的顺序以产生递增序列,但可以省略数字。

例如,给定列表 [1, 5, 3, 4],最长的递增子序列是 [1, 3, 4],因此结果长度为 3。

这是我目前的尝试:

def longest_seq(lst, num=0):
    if not lst:
        return num
    if len(lst) == 1:
        return num + 1

    if lst[0] < lst[1]:
        return longest_seq(lst[1:], num + 1)
    if lst[0] >= lst[1]:
        if lst[0] < lst[2]:
            return longest_seq([lst[0]] + lst[2:], num)
        else:
            return longest_seq(lst[1:], num)

该函数似乎适用于某些输入,但我认为逻辑是有缺陷的。我试图解决这些问题,但我发现想出一个只使用递归和 len() 并且不修改输入列表的解决方案具有挑战性。

我知道当 lst[0] >= lst[1] 时,我的函数应该考虑两种可能性:

  • 放弃当前号码并从下一个号码开始一个新序列,或者
  • 丢弃下一个数字,并尝试使用下一个数字扩展当前序列。

但我正在努力在我的函数中实现这个逻辑。谁能建议我如何改进我当前的实施以正确处理这些情况?

提前感谢您的帮助。

** 对于造成的任何混淆,我们深表歉意。我删除了我提到的违反规则的部分。我想澄清一下,我是初学者,所以我可能会不时犯错误。关于这个问题,我试图通过限制自己只使用 len() 函数并使用递归调用来解决这个问题。

Python 列表 算法 递归 序列

评论

0赞 trincot 7/4/2023
“它有时会跳过列表中的元素 [...],这违反了要求”:怎么会这样?你有没有告诉我们“......数字可以省略吗“?跳过和省略有区别吗?
1赞 trincot 7/4/2023
“它有时 [...]修改列表“:你能指出列表在哪里被修改了吗?我没有看到任何修改,只看到新列表的创建。
1赞 Ripi2 7/4/2023
我认为你应该重新思考你的逻辑。当您有几个连续的无效值时,它不起作用:[1, 5, 4, 3, 7, 8, 9]。 您必须将最后一个有效值传递给递归(例如,测试 4,.3 时为 “1,...子列表
0赞 user3386109 7/4/2023
即使您不能使用该功能,您仍然可以比较不同的结果以找到最佳结果。max()

答:

1赞 AlefiyaAbbas 7/4/2023 #1

我试图用不同的方法来回答这个问题。基本上,我采用了两个变量,分别表示包含第一个元素和不包括第一个元素的最长递增子序列的长度。我已经尝试了一些测试用例,我将在下面的帖子中包括这些用例。如果以下方法有帮助,请告诉我:include_firstexclude_first

def longest_seq(lst):
    if not lst:  
        return 0
    if len(lst) == 1:  
        return 1
    include_first = 1 + longest_seq(lst[1:]) if lst[0] < lst[1] else 0
    exclude_first = longest_seq(lst[1:])
    return max(include_first, exclude_first)

测试用例:

print("Test Case 1:" ,longest_seq([1, 5, 3, 4]))
print("Test Case 2:", longest_seq([5, 2, 1, 0])) 
print("Test Case 3:", longest_seq([1, 2, 3, 4, 5]))  
print("Test Case 4:", longest_seq([5, 2, 8, 6, 3, 6, 9, 7])) 

输出:

Test Case 1: 3
Test Case 2: 1
Test Case 3: 5
Test Case 4: 4

评论

0赞 Kelly Bundy 7/4/2023
例如,失败,返回 。longest_seq([3,4,1,2])3
0赞 AlefiyaAbbas 7/4/2023
谢谢你让我知道。我已经编辑了我的答案,请检查。
0赞 Kelly Bundy 7/4/2023
“不允许使用循环、max()、帮助程序函数或任何其他内置函数” - 您正在使用除循环之外的所有这些函数。
0赞 AlefiyaAbbas 7/4/2023
我会改变我的答案,很抱歉给您带来不便
1赞 wLui155 7/4/2023 #2

传入输入列表的一部分并删除输入是正确的想法。但是,我建议修改您的函数,以便它跟踪正在考虑的子序列的当前最大元素,因为试图通过保持最大元素(我认为您正在做的事情)来实现这一目标通常行不通。我已经继续提供了关于这可能是什么样子的骨架,但将一些递归调用/细节留空。lst[0]

def longest_seq(lst, largest = None, num = 0):
    if not lst:
        return num

    rest = lst[1:] # the callee operates on the sublist of the lst, with lst[0] excluded
    if num == 0:
        include = longest_seq(rest, lst[0], 1) # In the callee, operate on rest, using lst[0] as the largest element. subsequence length is also 1 in the callee.
        exclude = None # TBD - how would the recursive call for i
        return None # TBD - larger between include/exclude

    # num > 0 => largest entry populated
    exclude = None # figure out the recursive call of not including lst[0]
    if lst[0] > largest: # can include current
        include = None # figure out recursive call
        return None # TBD - larger between include/exclude

    return exclude # could not include lst[0] in the subsequence so only exclude can be returned
1赞 Alain T. 7/4/2023 #3

诀窍是在函数签名中添加一个可选参数,该参数将跟踪最小值(序列中先前包含的数字)。然后,该函数需要将递归时包含与排除第一个数字的结果与列表的其余部分进行比较。

def longest_seq(L,previous=None):
    if not L: return 0
    included = excluded = longest_seq(L[1:],previous)
    if previous is None or L[0]>previous:
        included = 1 + longest_seq(L[1:],L[0])
    return included if included>excluded else excluded   

输出:

print(longest_seq([1,5,3,4]))         # 3
print(longest_seq([1,5,3,7,8,9]))     # 5
print(longest_seq([8,1,5,2,7,3,9,4])) # 4