[英]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])
我看到此代碼有四個問題。
b =
行上,第二個參數使用len(left_L)
而不是len(right_L)
。 left_L
和right_L
之間的元素。 您不應該在right_L
列表理解的mid
添加一個。 right_L
上right+1
,而不僅僅是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
始終為列表的長度減去一。
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.