簡體   English   中英

Python - 將遞歸轉換為尾遞歸

[英]Python - convert recursion to a tail recursion

找出從網格的一個角到對角的方法數量,只向下或向右走。 我想出了一個使用遞歸來解決問題的初步想法:

def find_num_of_ways(x: int, y: int):
    if x == 0 or y == 0:
        return 1
    return find_num_of_ways(x - 1, y) + find_num_of_ways(x, y - 1)

當 x 和 y 增加時,這可能是堆棧溢出。 想找到更好的重構方式,一個是轉換為尾遞歸。 但是給定簽名中有2個變量,那么如何累加結果以使其成為尾遞歸?

我對此的分析是,計算一個答案需要很長時間,以至於您會在堆棧溢出之前很久就走開。 我將建議我們完全刪除遞歸並將其作為一個盒子和球的組合問題來做

(x + y - 1)!
------------
 y!(x - 1)!

加上相反的:

(y + x - 1)!
------------
 x!(y - 1)!

也就是說,Python 明智的:

from math import factorial as f

def find_num_of_ways(x, y):
    return f(x + y - 1) // (f(y) * f(x - 1)) + f(y + x - 1) // (f(x) * f(y - 1)) 

print(find_num_of_ways(10, 10))

輸出

> python3 test.py
184756
>

性能方面,對於參數:

find_num_of_waysTail(13, 14)

在我的機器上,OP 的原始遞歸解決方案需要 9 秒,@Mike67 的計數器解決方案大約需要 12 秒,而我上面的解決方案大約需要 0.05 秒。 全部產生結果 20058300。

由於所有路徑都在同一點結束,您可以計算最后一個點被觸摸的次數。

#### Recursion ####
def find_num_of_ways(x: int, y: int):
    if x == 0 or y == 0:
        return 1
    return find_num_of_ways(x - 1, y) + find_num_of_ways(x, y - 1)

ttl = find_num_of_ways(10,10)
print("Recursion", ttl)


#### Counter ####
ttl = 0
def find_num_of_waysCtr(x: int, y: int):
    global ttl
    if x == 0 or y == 0:
        ttl += 1
        return
    find_num_of_waysCtr(x - 1, y)
    find_num_of_waysCtr(x, y - 1)

find_num_of_waysCtr(10,10)
print("Counter  ", ttl)

輸出

Recursion 184756
Counter   184756

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM