【问题标题】:using recursion to find the maximum in a list使用递归查找列表中的最大值
【发布时间】:2014-12-29 22:30:48
【问题描述】:

我正在尝试使用递归查找列表中的最大元素。 输入需要是实际列表、左索引和右索引。

我写了一个函数,但不明白为什么它不起作用。我画了递归树,在脑海中运行了列表示例,这很有意义,这就是为什么现在更难找到解决方案的原因! (它基本上是在和自己战斗)。

我知道这很丑,但尽量忽略它。我的想法是在每次递归调用时将列表分成两半(这是必需的),而左侧索引将保持为 0,右侧将是新减半列表的长度,减去 1。

对该函数的第一次调用将来自尾部函数。

感谢您的帮助,我希望我没有错过一些非常愚蠢的东西,甚至更糟 - 甚至没有接近! 顺便说一句 - 没有使用切片来切割清单,因为我不允许。

def max22(L,left,right):
    if len(L)==1:
        return L[0]
    a = max22([L[i] for i in range(left, (left+right)//2)], 0 , len([L[i] for i in range(left, (left+right)//2)])-1)
    b = max22([L[i] for i in range(((left+right)//2)+1, right)], 0 ,len([L[i] for i in range(left, (left+right)//2)])-1)
    return max(a,b)



def max_list22(L):
    return max22(L,0,len(L)-1)

输入示例 - 对于 max_list22([1,20,3]),输出将为 20。

【问题讨论】:

  • 能否请您添加一个特定输入列表的示例以及您收到的意外结果/错误消息?
  • 为什么不用L[left:(left+right)//2] 而不是[L[i] for i in range(left, (left+right)//2)]?太难读了?
  • 这不是你布置的作业吗?
  • anmol,它是,但我尝试了很多次,我正在寻求帮助。我是学生,我所做的一切都是功课):
  • 和 Rawing,我不能使用切片,我知道它看起来很难看,只是搜索以了解我的代码有什么问题

标签: python recursion


【解决方案1】:

首先,为了清楚起见,我建议将您的列表理解分配给变量,这样您就不必将每个变量都写两次。这应该使代码更容易调试。您也可以对 (left+right)//2 值执行相同操作。

def max22(L,left,right):
    if len(L)==1:
        return L[0]
    mid = (left+right)//2
    left_L = [L[i] for i in range(left, mid)]
    right_L = [L[i] for i in range(mid+1, right)]
    a = max22(left_L,  0 , len(left_L)-1)
    b = max22(right_L, 0 , len(left_L)-1)
    return max(a,b)

def max_list22(L):
    return max22(L,0,len(L)-1)

print max_list22([4,8,15,16,23,42])

我发现这段代码有四个问题。

  1. 在您的b = 行中,第二个参数使用len(left_L) 而不是len(right_L)
  2. 您在left_Lright_L 之间缺少一个元素。您不应该在 right_L 列表理解中向 mid 添加一个。
  3. 您缺少列表的最后一个元素。您应该在 right_L 中上升到 right+1,而不仅仅是 right
  4. 您的mid 值在偶数大小的列表的情况下相差一。前任。 [1,2,3,4] 应该分成 [1,2] 和 [3,4],但是使用您的 mid 值,您将获得 [1][2,3,4]。 (假设您已经修复了前面要点中的缺失元素问题)。

解决这些问题的方法如下:

def max22(L,left,right):
    if len(L)==1:
        return L[0]
    mid = (left+right+1)//2
    left_L = [L[i] for i in range(left, mid)]
    right_L = [L[i] for i in range(mid, right+1)]
    a = max22(left_L,  0 , len(left_L)-1)
    b = max22(right_L, 0 , len(right_L)-1)
    return max(a,b)

def max_list22(L):
    return max22(L,0,len(L)-1)

print max_list22([4,8,15,16,23,42])

如果你坚持不使用临时变量,它看起来像:

def max22(L,left,right):
    if len(L)==1:
        return L[0]
    a = max22([L[i] for i in range(left, (left+right+1)//2)],  0 , len([L[i] for i in range(left, (left+right+1)//2)])-1)
    b = max22([L[i] for i in range((left+right+1)//2, right+1)], 0 , len([L[i] for i in range((left+right+1)//2, right+1)])-1)
    return max(a,b)

def max_list22(L):
    return max22(L,0,len(L)-1)

print max_list22([4,8,15,16,23,42])

风格提示:max22 不一定需要三个参数,因为left 始终为零,right 始终是列表长度减一。

def max22(L):
    if len(L)==1:
        return L[0]
    mid = (len(L))//2
    left_L = [L[i] for i in range(0, mid)]
    right_L = [L[i] for i in range(mid, len(L))]
    a = max22(left_L)
    b = max22(right_L)
    return max(a,b)

print max22([4,8,15,16,23,42])

【讨论】:

  • 谢谢!哈哈,我不坚持一个丑陋的代码(:很好的解释,我太棒了
【解决方案2】:

问题是您根本没有处理空列表。 max_list22([]) 无限递归,[L[i] for i in range(((left+right)//2)+1, right)] 最终产生一个空列表。

【讨论】:

  • 谢谢你,这真的有助于我理解事物。
【解决方案3】:

您的问题是您无法处理不均匀的拆分。使用您的代码,列表可能会变为空,但您也可以在大小 1 和 2 上停止,而不是更自然的 0 和 1(因为您返回最大值,零大小的列表没有最大值)。

def max22(L,left,right):

    if left == right:
        # handle size 1
        return L[left]

    if left + 1 == right:
        # handle size 2
        return max(L[left], L[right])

    # split the lists (could be uneven lists!)
    split_index = (left + right) / 2
    # solve two easier problems
    return max (max22(L, left, split_index), max22(L, split_index, right))

print max22([1,20, 3], 0, 2)

注意事项:

失去列表理解,您不必创建新列表,因为列表中有索引。

在处理递归时,你要考虑:

1 - 停止条件,在这种情况下有两个,因为列表拆分可能不均匀,使得递归在不均匀的条件下停止。

2 - 更简单的问题步骤。假设我可以解决一个更简单的问题,我该如何解决这个问题?这通常是递归函数末尾的内容。在这种情况下,在两个较小的(按索引的)列表上调用相同的函数。如果您熟悉递归,它看起来很像归纳证明。

Python 更喜欢明确地完成事情。虽然 Python 有一些功能特性,但最好让代码的读者知道你在做什么,而不是让人们摸不着头脑。

祝你好运!

【讨论】:

  • 托达!你真的帮助了我,我会确保在再次处理递归时记住你的建议。
  • @NiliSabbah Ein baaya :)
  • @NiliSabbah 如果你找到一个可以解决你的问题的答案,你应该接受它:)
猜你喜欢
  • 2015-05-03
  • 1970-01-01
  • 2013-11-04
  • 1970-01-01
  • 1970-01-01
  • 2021-11-11
  • 2021-12-08
  • 2019-12-18
  • 1970-01-01
相关资源
最近更新 更多