這道題是LeetCode裏的第198道題。
題目描述:
你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。
給定一個代表每個房屋存放金額的非負整數數組,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。
示例 1:
輸入: [1,2,3,1] 輸出: 4 解釋: 偷竊 1 號房屋 (金額 = 1) ,然後偷竊 3 號房屋 (金額 = 3)。 偷竊到的最高金額 = 1 + 3 = 4 。示例 2:
輸入: [2,7,9,3,1] 輸出: 12 解釋: 偷竊 1 號房屋 (金額 = 2), 偷竊 3 號房屋 (金額 = 9),接着偷竊 5 號房屋 (金額 = 1)。 偷竊到的最高金額 = 2 + 9 + 1 = 12 。
動態規劃法:
狀態轉移方程:max(dp[ i - 1 ], dp[ i - 2 ] + nums[ i ])
使用 dp 數組來保存當到第 i 時的最優解,也是第 i + 1 最優子結構。
解題代碼:
class Solution {
public int rob(int[] nums) {
int len = nums.length;
if(len == 0)return 0;
if(len == 1)return nums[0];
if(len == 2)return nums[0] > nums[1] ? nums[0] : nums[1];
int[] dp = new int[len];
dp[0] = nums[0];
dp[1] = nums[1] > nums[0] ? nums[1] : nums[0];
for(int i = 2; i < len; i++){
dp[i] = dp[i-2]+nums[i] > dp[i-1] ? dp[i-2]+nums[i] : dp[i-1];
}
return dp[len-1];
}
}
提交結果:
個人總結:
最後的優化可以只使用常數的空間來保存數據,但是這樣不直觀。
記憶化搜索法:
class Solution {
/**
* memo[i] 表示考慮搶劫 nums[i...n] 所能獲得的最大收益
*/
private int[] memo;
/**
* 方式一:記憶化搜索
* ① 狀態:考慮搶劫 nums[index...num.length) 這個範圍內的所有房子
* ② 狀態轉移:tryRob(n) = Max{rob(0) + tryRob(2), rob(1) + tryRob(3)... rob(n-3) + tryRob(n-1), rob(n-2), rob(n-1)}
*/
public int rob1(int[] nums) {
memo = new int[nums.length];
Arrays.fill(memo, -1);
return tryRob(nums, 0);
}
private int tryRob(int[] nums, int index) {
if (index >= nums.length) {
return 0;
}
// 記憶化搜索可以避免重疊子問題的重複運算
if (memo[index] != -1) {
return memo[index];
}
// 下面是對狀態轉移方程的描述
int res = 0;
for (int i = index; i < nums.length; i++) {
res = Math.max(res, nums[i] + tryRob(nums, i + 2));
}
memo[index] = res;
return res;
}
}
多學一種方法不礙事。