[英]Dynamic Programming: Smallest cost path through matrix -- memoization?
有没有一种简单的方法来记忆结果? 我的动态编程解决方案可能会使用相同的参数多次调用相同的 function。
我认为记忆会增加速度。 但是,我不确定最好的方法是什么。 这是原始的 function,虽然它没有被记住,但它可以工作:
def dim(M):
rows = len(M)
cols = len(M[0])
return rows, cols
def minimumCostPath(matrix, i=0, j=0, total=0):
r,c = dim(matrix)
if i+1 < r and j+1 < c:
down = matrix[i+1][j]
right = matrix[i][j+1]
return min(minimumCostPath(matrix, i+1, j, total+down),
minimumCostPath(matrix, i, j+1, total+right))
elif i+1 < r:
right = matrix[i+1][j]
return minimumCostPath(matrix, i+1, j, total+right)
elif j+1 < c:
down = matrix[i][j+1]
return minimumCostPath(matrix, i, j+1, total+down)
else:
return total + matrix[0][0]
test = [ [23,70,54],
[86,5,13],
[86,62,77],
[60,37,32],
[88,58,98] ]
total = minimumCostPath(test)
>>>
318
下面是我用零矩阵(嵌套列表)来记忆这个 function 的尝试。
def solution(matrix):
cache = [[0 for j in range(len(matrix[0]))] for i in range(len(matrix))]
return helper(matrix, cache, i=0, j=0, total=0)
def helper(matrix, cache, i=0, j=0, total=0):
r,c = dim(matrix)
if i+1 < r and j+1 < c:
down = matrix[i+1][j]
right = matrix[i][j+1]
if cache[i+1][j] > 0:
go_down = cache[i+1][j] + down
else:
go_down = helper(matrix, cache, i+1, j, total+down)
cache[i+1][j] = go_down
if cache[i][j+1] > 0 :
go_right = cache[i][j+1] + right
else:
go_right = helper(matrix, cache, i, j+1, total+right)
cache[i][j+1] = go_right
return min(go_down, go_right)
elif i+1 < r:
down = matrix[i+1][j]
if cache[i+1][j] > 0:
go_down = cache[i+1][j] + down
else:
go_down = helper(matrix, cache, i+1, j, total+down)
cache[i+1][j] = go_down
return go_down
elif j+1 < c:
right = matrix[i][j+1]
if cache[i][j+1] > 0 :
go_right = cache[i][j+1] + right
else:
go_right = helper(matrix, cache, i, j+1, total+right)
cache[i][j+1] = go_right
return go_right
else:
return total + matrix[0][0]
solution(test)
两个问题。
TypeError: '<' not supported between instances of 'NoneType' and 'int'
第 23 行将 go_right 或 go_down 评估为 None,这很奇怪。最后,我知道有一种自下而上的方法,它不使用递归,而是迭代地填充表格单元格。 在这一点上,我想知道递归解决方案如何利用记忆,而不是从头开始实现自下而上。
首先,您的错误:在其中一个分支中, return go_down
缩进太远,因此go_down
的非递归计算不会返回该值; 相反,它会从 function 的末尾脱落并返回隐式None
就记忆化而言, functools
中有cache
和lru_cache
装饰器。 上次我使用它(大约 5 年前和许多版本)它有点慢,只对外部数据(磁盘或网络)真正有用; 您必须衡量它是否对您而言令人满意。 从那时起,它可能已经改善了很多。
如果您确实需要手动实现缓存(如果functools.cache
装饰器被证明太慢),那么缓存分离的模式可能会更好,以避免混合关注点:
minimumCostPath_cache = {}
def minimumCostPath(matrix, i=0, j=0):
try:
return minimumCostPath_cache[i, j]
except KeyError:
result = minimumCostPath_cache[i, j] = minimumCostPath_raw(matrix, i, j)
return result
def minimumCostPath_raw(matrix, i=0, j=0):
...
为避免全局变量和具有不同矩阵的调用相互干扰,您可以在 class 中执行此操作:
class MinimumCostPath:
def __init__(self, matrix):
self.cache = {}
self.matrix = matrix
def calculate(self, i=0, j=0):
try:
return self.cache[i, j]
except KeyError:
result = self.cache[i, j] = self.calculate_uncached(i, j)
return result
def calculate_uncached(self, i=0, j=0):
...
如果您有 Python 3.9,请了解@cache
装饰器以实现无忧记忆
@cache
def factorial(n):
return n * factorial(n-1) if n else 1
>>> factorial(10) # no previously cached result, makes 11 recursive calls
3628800
>>> factorial(5) # just looks up cached value result
120
>>> factorial(12) # makes two new recursive calls, the other 10 are cached
479001600
from functools import lru_cache
@lru_cache(maxsize=None, typed=False)
def minimumCostPath(matrix, i=0, j=0):
r,c = len(M), len(M[0])
if i+1 < r and j+1 < c:
down = matrix[i+1][j]
right = matrix[i][j+1]
return min(minimumCostPath(matrix, i+1, j) + down,
minimumCostPath(matrix, i, j+1) + right)
elif i+1 < r:
right = matrix[i+1][j]
return minimumCostPath(matrix,i+1, j) + right
elif j+1 < c:
down = matrix[i][j+1]
return minimumCostPath(matrix,i, j+1) + down
else:
return matrix[0][0]
将总参数移出并使用 lru_cache 保存以前的 function 调用。 它有 8 次安打,15 次未命中,目前尺寸为 15。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.