简体   繁体   English

Python - 将递归转换为尾递归

[英]Python - convert recursion to a tail recursion

To find the number of ways to get from one corner of a grid to the opposite corner, by going down or right only.找出从网格的一个角到对角的方法数量,只向下或向右走。 I come up with an initial idea to use the recursion to solve the problem:我想出了一个使用递归来解决问题的初步想法:

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)

This can be stack overflow when x and y increase.当 x 和 y 增加时,这可能是堆栈溢出。 Want to find a better way to refactor this, one is convert to tail recursion.想找到更好的重构方式,一个是转换为尾递归。 But given 2 variables in the signature, so how to accumulate the result in order to make it tail recursion?但是给定签名中有2个变量,那么如何累加结果以使其成为尾递归?

My analysis of this is that it takes so long to compute an answer that you'll walk away long before the stack overflows.我对此的分析是,计算一个答案需要很长时间,以至于您会在堆栈溢出之前很久就走开。 I'm going to suggest we remove the recursion altogether and do this as a boxes and balls combinatorial problem我将建议我们完全删除递归并将其作为一个盒子和球的组合问题来做

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

plus the reverse:加上相反的:

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

that is, Python-wise:也就是说,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))

OUTPUT输出

> python3 test.py
184756
>

Performance-wise, for the arguments:性能方面,对于参数:

find_num_of_waysTail(13, 14)

On my machine, the OP's original recursive solution takes 9 seconds, @Mike67's counter solution takes about 12 seconds, and my solution above takes about 0.05 seconds.在我的机器上,OP 的原始递归解决方案需要 9 秒,@Mike67 的计数器解决方案大约需要 12 秒,而我上面的解决方案大约需要 0.05 秒。 All produce the result 20058300.全部产生结果 20058300。

Since all the paths end at the same point, you can just count how many times the last point is touched.由于所有路径都在同一点结束,您可以计算最后一个点被触摸的次数。

#### 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)

Output输出

Recursion 184756
Counter   184756

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM