我用三种不同的方式解决problem,其中两种是递归的,我自己也记住它们。另一个不是递归的,而是使用math.factorial。我需要知道是否需要为其添加显式的memoization。
感谢。
答案 0 :(得分:4)
在此链接上搜索math_factorial,您将在python中找到它的实现:
http://svn.python.org/view/python/trunk/Modules/mathmodule.c?view=markup
P.S。这是为python2.6
答案 1 :(得分:4)
Python的math.factorial不是memoized,它是一个简单的for循环,将值从1乘以你的arg。如果需要记忆,则需要明确地进行记忆。
这是一种使用字典setdefault方法进行memoize的简单方法。
import math
cache = {}
def myfact(x):
return cache.setdefault(x,math.factorial(x))
print myfact(10000)
print myfact(10000)
答案 2 :(得分:2)
Python的math.factorial没有被记忆。
我将引导您完成一些试验和错误示例,了解为什么要获得一个真正的记忆和工作因子功能,您必须从头开始重新定义它,并考虑到几个方面。
另一个答案实际上是不正确的。这里,
import math
cache = {}
def myfact(x):
return cache.setdefault(x,math.factorial(x))
行
return cache.setdefault(x,math.factorial(x))
每次都会计算x
和math.factorial(x)
,因此您的性能不会提高。
您可能会想到这样的事情:
if x not in cache:
cache[x] = math.factorial(x)
return cache[x]
但实际上这也是错误的。是的,您可以避免重新计算相同x
的阶乘,但请考虑一下,例如,如果您要计算myfact(1000)
并且很快就会计算myfact(999)
。myfact(1000)
。它们都完全被计算出来,因此myfact(999)
自动计算def memoize(f):
"""Returns a memoized version of f"""
memory = {}
def memoized(*args):
if args not in memory:
memory[args] = f(*args)
return memory[args]
return memoized
@memoize
def my_fact(x):
assert x >= 0
if x == 0:
return 1
return x * my_fact(x - 1)
这一事实并没有带来任何好处。
然后写这样的东西很自然:
# The 'max' key stores the maximum number for which the factorial is stored.
fact_memory = {0: 1, 1: 1, 'max': 1}
def my_fact(num):
# Factorial is defined only for non-negative numbers
assert num >= 0
if num <= fact_memory['max']:
return fact_memory[num]
for x in range(fact_memory['max']+1, num+1):
fact_memory[x] = fact_memory[x-1] * x
fact_memory['max'] = num
return fact_memory[num]
这将起作用。不幸的是,它很快就达到了最大递归深度。
那么如何实现呢?
这是一个真正的memoized阶乘的例子,它利用了阶乘的工作方式,并且不会使用递归调用来消耗所有堆栈:
def memoize(f):
"""Returns a memoized version of f"""
memory = {}
def memoized(*args):
if args not in memory:
memory[args] = f(*args)
return memory[args]
return memoized
@memoize
def my_fact(x, fac=1):
assert x >= 0
if x < 2:
return fac
return my_fact(x-1, x*fac)
我希望你觉得这很有用。
修改强>
正如笔记一样,实现同样优化的一种方法同时具有递归的简洁性和优雅性,将该函数重新定义为tail-recursive函数。
RuntimeError: maximum recursion depth exceeded
尾部递归函数实际上可以被解释器/编译器识别并自动转换/优化为迭代版本,但并非所有解释器/编译器都支持此功能。
不幸的是,python不支持尾递归优化,所以你仍然得到:
{{1}}
当my_fact的输入为高时。
答案 3 :(得分:1)
我迟到了,但这里是我在Python中实现高效的memoized factorial函数的2c。这种方法更有效,因为它依赖于类似数组的结构(即list
)而不是散列容器(即dict
)。不涉及递归(免除一些Python函数调用开销)并且没有涉及缓慢的for循环。并且它(可以说)在功能上是纯粹的,因为没有涉及外部副作用(即它不修改全局变量)。它会缓存所有中间因子,因此如果您已经计算了factorial(n)
,那么任何0 <= m <= n和O(mn)都需要O(1)来计算factorial(m)
对于任何m> ñ。
def inner_func(f):
return f()
@inner_func
def factorial():
factorials = [1]
def calculate_factorial(n):
assert n >= 0
return reduce(lambda cache, num: (cache.append(cache[-1] * num) or cache),
xrange(len(factorials), n+1), factorials)[n]
return calculate_factorial