我有一个可行的递归解决方案,但事实证明,很多子问题正在重新计算。我需要有关记忆的帮助。
这是问题说明:
您是一名专业劫匪,打算在一条街道上抢劫房屋。 每个房子都藏有一定数量的钱,唯一的限制 阻止您抢劫每一个是相邻的房子有 安全系统已连接,它将自动与警察联系 如果同一晚晚上有两间相邻的房屋被闯入。
给出一个表示金额的非负整数列表 确定每间房子的最高金额 今晚不通知警察。
示例:
输入:
[2,7,9,3,1]
输出:12
说明:Rob house 1(金钱= 2), 抢劫房屋3(金钱= 9)和抢劫房屋5(金钱= 1)。 您可以抢夺的总金额=2 + 9 + 1 = 12
。
另一个:
输入:
[1,2,3,1]
输出:4
说明:Rob house 1(money = 1)和 然后抢房子3(钱= 3)。 您可以抢夺的总金额=1 + 3 = 4
。
还有一个
输入:
[2, 1, 1, 2]
输出:4
说明:Rob house 1(金钱= 2)和 然后抢房子4(钱= 2)。 您可以抢夺的总金额=2 + 2 = 4
。
现在,就像我说的那样,我有一个完美的递归解决方案:构建递归解决方案时。我不会想太多。我只是试图了解较小的子问题。
option_1
:我将值添加到当前的index
中,然后转到index + 2
option_2
:我没有在当前的index
中添加值,而是从index + 1
开始搜索
最高金额= max(option_1, option_2)
money = [1, 2, 1, 1] #Amounts that can be looted
def helper(value, index):
if index >= len(money):
return value
else:
option1 = value + money[index]
new_index1 = index + 2
option2 = value
new_index2 = index + 1
return max(helper(option1, new_index1), helper(option2, new_index2))
helper(0, 0) #Starting of at value = 0 and index = 0
这完美工作..并返回正确的值3
。
然后我尝试进行记忆。
money = [1, 2, 1, 1]
max_dict = {}
def helper(value, index):
if index in max_dict:
return max_dict[index]
elif index >= len(l1):
return value
else:
option1 = value + money[index]
new_index1 = index + 2
option2 = value
new_index2 = index + 1
max_dict[index] = max(helper(option1, new_index1), helper(option2, new_index2))
return max_dict[index]
helper(0, 0)
我只是有一个名为max_dict
的字典来存储该值,并且每个递归调用都会检查该值是否已经存在,然后相应地获取它并将其打印出来。.
但是我得到的错误解决方案是2
而不是3
。我去pythontutor.com
并输入了解决方案,但似乎无法获得递归树及其失败之处。
有人能在保持整体结构不变的情况下给我正确的回忆实现吗?换句话说,我不想更改递归函数定义
答案 0 :(得分:3)
您的记忆方法将不起作用,因为当达到某个索引i
时,如果您已经为i
计算了一些结果,则您的算法将无法考虑以下事实:通过抢走阵列左侧的一组更优化的房屋,可以获得更好的结果。
解决此难题的方法是避免将正在运行的value
(您被抢的钱)通过父母对孩子的递归调用而向下传递。这个想法是在没有祖先节点任何输入的情况下计算子问题结果,然后在备份调用堆栈的过程中从较小的结果中构建较大的结果。
然后就可以对索引i
进行记忆化,因为给定的索引i
将始终具有一组唯一的子问题,这些子问题的解决方案不会受到数组左部分祖先的选择的破坏。这样可以保留DP工作所需的最佳子结构。
此外,我建议避免使用全局变量,而应将数据直接传递到函数中。
def maximize_robberies(houses, memo, i=0):
if i in memo:
return memo[i]
elif i >= len(houses):
return 0
memo[i] = max(
houses[i] + maximize_robberies(houses, memo, i + 2),
maximize_robberies(houses, memo, i + 1)
)
return memo[i]
print(maximize_robberies([1, 2, 1, 1], {}))
答案 1 :(得分:2)
可以为同一helper
用不同的value
参数调用index
。因此必须删除value
(从存储的max_dict
中减去)。一种方法是在返回之前而不是更早之前添加value
:
money = [2, 1, 1, 2]
max_dict = {}
def helper(value, index):
if index in max_dict:
return value + max_dict[index]
elif index >= len(money):
return value
else:
option1 = money[index]
new_index1 = index + 2
option2 = 0
new_index2 = index + 1
max_dict[index] = max(helper(option1, new_index1), helper(option2, new_index2))
return value + max_dict[index]
helper(0, 0)
@ggorlen的答案给出了更详细的解释
答案 2 :(得分:1)
我使用以下方法解决了此动态编程问题。这是在O(n)时间发生的。尝试一下。
class Solution:
# @param {integer[]} nums
# @return {integer}
def rob(self, nums):
n = len(nums)
if n==0:
return 0;
if n == 1:
return nums[0]
s = [0]*(n+1)
s[1] = nums[0]
s[2] = nums[1]
for i in range(3,n+1):
s[i] = (max(s[i-2],s[i-3]) + nums[i-1])
return max(s[n],s[n-1])
money = [2, 1, 1, 2]
sol = Solution()
print(sol.rob(money))