Python-将递归转换为尾递归

问题描述

查找仅通过向下或向右从栅格的一个角到达另一角的方法。我提出了使用递归来解决问题的初步思路:

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