4 回答

TA貢獻1828條經驗 獲得超6個贊
您的代碼至少存在五個問題:
solution(arr, sum, i)
對in的調用calcsum
不會修改calcsum
局部變量sum
,因此calcsum
始終返回 0;您在 中 中編寫了
return
而不是return sum
在最終情況下進行遞歸solution
,因此在這種情況下solution
將返回None
而不是返回總和您將遞歸調用編寫為
solution(arr,sum,i+1)
而不是return solution(arr,sum,i+1)
orsome_variable = solution(arr,sum,i+1)
,因此無論如何都會忽略遞歸調用的返回值;return
除了塊內的語句之外,沒有任何語句if
,因此該函數solution
不會有返回值(或者更準確地說,它將返回None
);您似乎相信修改
sum
內部solution
會修改sum
整個程序中調用的任何變量。這是錯誤的。sum
是函數的局部變量,修改它對程序的其余部分沒有影響。在 python 中調用變量
sum
是一個壞主意;這是內置函數的名稱,因此您應該嘗試為變量找到另一個名稱。
為了說明第四點,請嘗試以下代碼:
def mostly_harmless(n):
n = 7
n = 8
mostly_harmless(n)
print('Does this set n to 7? Am I about to print 8 or 7?')
print(n)
print()
mostly_harmless(12)
print('did we set 12 = 7? did we just break all of mathematics?')
print('making sure 12 is still 12:')
print(12)
print('making sure n is still n:')
print(n)
考慮到這一點,我們可以修復您的代碼:
def calcsum(arr):
return solution(arr, 0, 0)
def solution(arr, sum, i):
if i == len(arr):
return sum
else:
return solution(arr, sum + arr[i], i+1)
print(calcsum([1,2,3,4,5]))
實際上,我們可以使用默認參數進一步簡化代碼:
def calcsum(arr, sum=0, i=0):
if i == len(arr):
return sum
else:
return calcsum(arr, sum + arr[i], i+1)
print(calcsum([1,2,3,4,5]))
但請注意,python并不是一門喜歡遞歸的語言。在其他一些編程語言中,遞歸非常好,并且與 for 循環和 while 循環一樣高效。但在 python 中卻并非如此。在Python中,遞歸比循環慢得多,并且使用更多的內存。我們可以用 for 循環重寫你的程序:
def calcsum(arr):
sum = 0
for i in range(len(arr)):
sum += arr[i]
return sum
print(calcsum([1,2,3,4,5]))
或者甚至更好:
def calcsum(arr):
sum = 0
for v in arr:
sum += v
return sum
print(calcsum([1,2,3,4,5]))
另請注意,在 python 中調用變量sum是一個壞主意,因為sum是 python 中內置函數的名稱。您可以在python 文檔中找到內置函數列表;嘗試為您的變量指定其他名稱。
毫不奇怪,該函數sum自行計算總和:
print(sum([1,2,3,4,5]))
那么為什么調用變量這么糟糕呢sum?好吧,那么我們就失去了對同名內置函數的訪問:
sum = 7
print(sum([1,2,3,4,5]))
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# TypeError: 'int' object is not callable
通常sum指內置函數;但現在它引用一個等于7;的變量 當我嘗試調用 時sum([1,2,3,4,5]),就好像我嘗試調用一樣7([1,2,3,4,5]),這是沒有意義的,因為它7不是一個函數。

TA貢獻1848條經驗 獲得超6個贊
您可以使其按您的方式工作,即增加sum中的變量calcsum,如果您將solution其放入其中并增加外部sum而不是擁有自己的變量。arr那么也無需通過。
def calcsum(arr):
def solution(i):
nonlocal sum
if i == len(arr):
return
sum = sum + arr[i]
solution(i+1)
sum = 0
solution(0)
return sum
print(calcsum([1,2,3,4,5]))

TA貢獻1854條經驗 獲得超8個贊
正如已經提到的,您應該返回總和。這是一個迭代器版本:
def calcsum(arr):
return solution(iter(arr), 0)
def solution(it, sum):
for x in it:
return solution(it, sum + x)
return sum
print(calcsum([1,2,3,4,5]))
僅使用一個函數和一個參數的更短方法,在遞歸x 后添加:
def calcsum(it):
it = iter(it)
for x in it:
return x + calcsum(it)
return 0
print(calcsum([1,2,3,4,5]))
兩種解決方案都需要線性時間,而類似的解決方案只需要arr并將其分成arr[0]和arr[1:],而后者需要整體二次時間。通過對 1000 個值的列表求和來比較此迭代器版本與該列表版本的一個小基準測試:
0.28 ms calcsum_1
2.70 ms calcsum_2
基準代碼:
from timeit import repeat
def calcsum_1(it):
it = iter(it)
for x in it:
return x + calcsum_1(it)
return 0
def calcsum_2(arr):
if arr:
x, rest = arr[0], arr[1:]
return x + calcsum_2(rest)
return 0
arr = [1] * 1000
for _ in range(3):
for f in calcsum_1, calcsum_2:
t = min(repeat(lambda: f(arr), number=1000))
print('%.2f ms ' % t, f.__name__)
print()

TA貢獻1784條經驗 獲得超7個贊
請記住,遞歸至少有兩種情況:
基本情況:返回合計值
遞歸情況:返回遞歸結果
這兩種情況都不會返回值!試試這個:
def solution(arr, sum_, i):
if i == len(arr):
return sum_
sum_ += arr[i]
return solution(arr, sum_, i+1)
此外,僅僅調用solution不會改變sumin的值calcsum,因此return sum總是給出0. 嘗試改為:
def calcsum(arr):
return solution(arr, 0, 0)
(順便說一句,這種創建函數的結構,將調用委托給帶有一些附加參數的助手,這讓我想起了很多 Haskell,你可以在其中編寫:
calcsum :: Num a => [a] -> a
calcsum = go 0 0
where go :: Num a => Int -> Int -> [a] -> a
go acc idx xs
| length xs >= idx = acc
| otherwise = go (acc + (xs !! idx)) idx+1 xs
另外你的邏輯有點復雜??紤]一下類似的事情:
def solution(arr):
if arr:
# Recursive case
x, rest = arr[0], arr[1:]
return x + solution(rest)
else:
# Base case
return 0
現在的基本情況是當arr為空時(而不是當您傳遞了數組外部的索引時)。您計算空列表的總和,該列表只能在邏輯上通過0。遞歸情況將第一個元素從列表中拉出,并將其添加到列表其余部分的解決方案中。
添加回答
舉報