打家劫舍
动态规划解法,二维dp
目的是为了求最大金额,状态应该是与最大金额有关的
状态转移:
由于每个元素都会有两种状态,而且这两种状态和前一个元素的状态有关,因此dp数组是二维的,每个元素也需要记录两种状态
dp[i][0]: 表示对第i个元素,不偷的最大金额
dp[i][1]: 表示对第i个元素,偷的最大金额
# 状态转移
dp[i][0] = max( dp[i-1][0], dp[i-1][1] ) # 无法确定那个大,取最大的
dp[i][1] = dp[i-1][0] + nums[i]
# 初始状态
dp[0][0] = 0
dp[0][1] = nums[0]
完整代码如下:
class Solution:
def rob(self, nums: List[int]) -> int:
length = len(nums)
if length == 0:
return 0
dp = [[0]*2 for _ in range(length)]
dp[0][0] = 0
dp[0][1] = nums[0]
for i in range(1, length):
dp[i][0] = max(dp[i-1][0], dp[i-1][1])
dp[i][1] = dp[i-1][0] + nums[i]
return max(dp[length-1][0], dp[length-1][1])
利用滚动数组,减少空间的消耗
class Solution:
def rob(self, nums: List[int]) -> int:
length = len(nums)
if length == 0:
return 0
dp = [[0]*2 for _ in range(2)]
dp[0][0] = 0
dp[0][1] = nums[0]
for i in range(1, length):
dp[i%2][0] = max(dp[(i-1) % 2][0], dp[(i-1) % 2][1])
dp[i%2][1] = dp[(i-1) % 2][0] + nums[i]
return max(dp[(length-1) % 2][0], dp[(length-1) % 2][1])
发现上面有点多余,可以再简单一点
class Solution:
def rob(self, nums: List[int]) -> int:
length = len(nums)
if length == 0:
return 0
dp = [[0]*2]
dp[0][0] = 0
dp[0][1] = nums[0]
for i in range(1, length):
tmep = dp[0][0]
dp[0][0] = max(dp[0][0], dp[0][1])
dp[0][1] = tmep + nums[i]
return max(dp[0][0], dp[0][1])
再简单一点
class Solution:
def rob(self, nums: List[int]) -> int:
length = len(nums)
if length == 0:
return 0
dp = [0]*2
dp[0] = 0
dp[1] = nums[0]
for i in range(1, length):
tmep = dp[0]
dp[0] = max(dp[0], dp[1])
dp[1] = tmep + nums[i]
return max(dp[0], dp[1])
还能优化一下
class Solution:
def rob(self, nums: List[int]) -> int:
length = len(nums)
if length == 0:
return 0
dp = [0]*2
dp[0] = 0
dp[1] = nums[0]
for i in range(1, length):
dp[0] , dp[1] = max(dp[0], dp[1]), dp[0]+ nums[i]
return max(dp[0], dp[1])
更简单的解法, 一维dp
dp[i] 表示前i个空间,并且第i个空间选取时,的最大值。
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
return 0
size = len(nums)
if size == 1:
return nums[0]
dp = [0] * size
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, size):
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
return dp[size - 1]
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/house-robber/solution/da-jia-jie-she-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
上述方法使用了数组存储结果。考虑到每间房屋的最高总金额只和该房屋的前两间房屋的最高总金额相关,因此可以使用滚动数组,在每个时刻只需要存储前两间房屋的最高总金额。
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
return 0
size = len(nums)
if size == 1:
return nums[0]
first, second = nums[0], max(nums[0], nums[1])
for i in range(2, size):
first, second = second, max(first + nums[i], second)
return second
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/house-robber/solution/da-jia-jie-she-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
滚动数组还是取模方式比较方便
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
return 0
size = len(nums)
if size == 1:
return nums[0]
dp = [0]*2
dp[0], dp[1] = nums[0], max(nums[0], nums[1])
for i in range(2, size):
dp[i%2] = max(dp[(i-1) % 2], dp[(i-2) % 2] + nums[i] )
return dp[(size-1) % 2]
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
return 0
size = len(nums)
if size == 1:
return nums[0]
dp = [0]*3
dp[0], dp[1] = nums[0], max(nums[0], nums[1])
for i in range(2, size):
dp[i%3] = max(dp[(i-1) % 3], dp[(i-2) % 3] + nums[i] )
return dp[(size-1) % 3]
DFS解法
DFS 与 迭代的区别
本质上和动态规划的解法是一样的,都是状态的转移,不同的是DFS的方式是从后往前推的递归形式,而动态规划的方式是从前往后推的迭代形式,动态规划更简洁一点。而DFS如果用树状图来描述,则思路比较清楚,就是代码写起来有点复杂。
另外在递归的过程中有大量的重复,因此需要用字典结构来进行剪枝,空间复杂度O(n),而迭代形式的滚动数组是O(1),迭代的一大好处就是可以使用滚动数组,减少空间的使用。
class Solution:
def rob(self, nums: List[int]) -> int:
length = len(nums)
if length == 0:
return 0
dict1 = {}
def _dfs(n,flg):
if n == 0 and flg == 0:
return 0
if n == 0 and flg == 1:
return nums[0]
if flg == 0:
v0 = 0; v1 = 0
if (n-1, 0) in dict1.keys():
v0 = dict1[(n-1, 0)]
else: v0 = _dfs(n-1, 0); dict1[(n-1, 0)] = v0
if (n-1, 1) in dict1.keys():
v1 = dict1[(n-1, 1)]
else: v1 = _dfs(n-1, 1); dict1[(n-1, 1)] = v1
v = max(v0,v1)
dict1[(n,0)] = v
return v
if flg == 1:
v = 0
if (n-1, 0) in dict1.keys():
v = dict1[(n-1, 0)] + nums[n]
else:
# print("here")
v = _dfs(n-1,0) ; dict1[(n-1, 0)] = v
v = v + nums[n]
dict1[(n, 1)] = v
return v
res = _dfs(length,0) # 这里需要注意 有技巧
# print(dict1)
return res