我正在尝试使用递归查找列表中的最大元素。 输入需要是实际列表,左索引和右索引。
我写了一个函数,无法理解为什么它不起作用。我绘制了递归树,在脑海中运行了列表示例,这很有意义,这就是为什么现在更难找到解决方案的原因! (它基本上是在打自己)。
我知道这很难看,但试着忽略它。我的想法是在每次递归调用时将列表分成两半(这是必需的),而左侧索引将保持为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.
答案 0 :(得分:4)
问题在于你根本不处理空列表。 max_list22([])
无限地递归,[L[i] for i in range(((left+right)//2)+1, right)]
最终产生一个空列表。
答案 1 :(得分:4)
首先,为了清楚起见,我建议将列表推导分配给变量,这样您就不必每次写两次。这应该使代码更容易调试。您也可以对(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])
我发现此代码存在四个问题。
b =
行,第二个参数使用的是len(left_L)
,而不是len(right_L)
。left_L
和right_L
之间的元素。您不应该在mid
列表理解中添加一个right_L
。right+1
中的right_L
,而不仅仅是right
。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
始终是列表的长度减去一。< / p>
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 :(得分:4)
你的问题是你不能处理不均匀的分裂。列表可能会使用您的代码变空,但您也可以停止使用大小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具有一些功能特性,但是最好让代码的读者知道你要评价的是什么,而不是让人们抓住他们头脑的大单行。
祝你好运!