LeetCode上动态规划的一个系列,从多个角度来考虑问题,从而更加熟练动态规划,加深理解和精通应用。
House Robber I
解法1: 递归
解法2: 递归+memorization
解法3: 动态规划1:
两个动态规划数组dp[i][0]
和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]
这样i
的状态只和i-1
的状态有关,因为i-1
有两个状态。
解法4:动态规划2:
因为i
的状态只和i-1
的状态有关,所以类似滚动数组的优化技巧,不需要用动态规划数组,用两个数prev
和prev2
代表前一个位置抢和不抢的收益。
解法5:动态规划3:
只用一个动态规划数组,dp[i]
表示抢第i
个位置的收益。
dp[i] = max(dp[i-2] + nums[i], dp[i-1])
这里i
的状态只有一个,但是i
的状态的更新和i-1
和i-2
都有关。
当更新完dp数组后,再从中选取最大值。
解法3和解法5的差别:
动态规划其实是一个多阶段选择的问题。解法3是按照阶段来搜索,解法5是按照可能的路径来搜索。解法3相对来说更容易,因为它的最优子问题是从暴力递归搜索中得到的。一般来说多阶段选择问题都用解法3, 特别是必须要在最后一个阶段终结的问题。解法5适合的是路径可以在任意阶段终结的问题。
House Robber II
相较于House Robber I 多了一个维度的状态,即第一个家抢或者不抢。
House Robber III
自上而下递归。
解法1:递归+memorization
解法2:动态规划
分析重复子问题是因为抢或不抢导致的。为了减少重复子问题,每次返回一个数组,保存了抢或不抢的收益,避免多次计算重复子问题。