繁体   English   中英

使用递归在列表中找到最大值

[英]using recursion to find the maximum in a list

我正在尝试使用递归在列表中找到最大的元素。 输入必须是实际列表,左索引和右索引。

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

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

该函数的第一个调用将来自tail函数。

感谢您的帮助,我希望我不会错过任何真正愚蠢的事情,甚至更糟的是-甚至没有关闭! 顺便说一句-不使用切片来削减列表,因为不允许我这样做。

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。

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

首先,为清楚起见,我建议将列表理解分配给变量,这样您就不必每次都写两次。 这应该使代码更易于调试。 您也可以对(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_Lright+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])

您的问题是您无法处理不均匀的拆分。 使用您的代码,列表可能会变成空的,但是您也可以停止使用大小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具有某些功能,但最好让代码的读者知道您要做什么,而不是拥有庞大的单行代码,这会使人们挠头。

祝好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM