繁体   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