198. 打家劫舍
- 打家劫舍
難度簡單786
你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。
給定一個代表每個房屋存放金額的非負整數數組,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。
示例 1:
輸入: [1,2,3,1] 輸出: 4 解釋: 偷竊 1 號房屋 (金額 = 1) ,然後偷竊 3 號房屋 (金額 = 3)。 偷竊到的最高金額 = 1 + 3 = 4 。
1.二維dp
首先dp三部曲是,1.找出重複子問題 2.狀態定義 3.定義dp方程
1.求解的問題是偷取最大金額,而子問題劃分後 就是偷取當前房子是最大值
2.狀態的定義 因爲要記錄當前是投還是沒投 所以採用二維dp
一維記錄當前在哪個房子,二維記錄當前是否偷沒。 0>沒偷 1>偷
3.dp方程
a[i][0] = Math.max(a[i-1][0],a[i-1][1]);//如果當前不偷,前一個可偷 也可不偷
a[i][1] = a[i-1][0]+nums[i];//當前偷 前一個不偷 加上當前的錢數
//time O(n) space O(n*2)
public int rob(int[] nums) {
if(nums.length == 0) return 0;
if(nums.length ==1) return nums[0];
int n = nums.length;
int [][] a = new int [n+1][2];//二維 0>不偷 1>偷
a[0][0] = 0;
a[0][1] = nums[0];
for(int i=1;i<n;i++){
a[i][0] = Math.max(a[i-1][0],a[i-1][1]); //如果當前不偷 前一個可偷 也可不偷
a[i][1] = a[i-1][0] + nums[i]; //如果當前偷 前一個不能偷 加上當前的房子的最大值
}
return Math.max(a[n-1][1],a[n-1][0]);
}
2.二維dp
上述是通過二維數組來記錄當前的最大值 而如果我們將問題簡單化,也就是每次都拿的是最大值,那麼只需要一個一維數組就可以解決了。
//1.子問題劃分 每次都拿到最大值
//2.dp[i] 記錄當前能拿到的最大值
//3.dp[i] = Math.max(dp[i-1],dp[i-2]+nums[i]);
// time : O(n) space : O(n)
public int rob(int[] nums) {
if(nums.length == 0) return 0;
if(nums.length ==1) return nums[0];
int n = nums.length;
int [] dp = new int [n+1];
//每次拿最大值
dp[0] = nums[0];
dp[1] = Math.max(dp[0],nums[1]);
int res = Math.max(dp[0],dp[1]);
for(int i=2;i<n;i++){
dp[i] = Math.max(dp[i-1],dp[i-2]+nums[i]);
res = Math.max(dp[i],res);
}
return res;
}
3.常數 dp
// time :O(n) space :O(1)
public int rob(int[] nums) {
int preMax = 0;
int curMax = 0;
for(int num : nums){
int tmp = curMax;
curMax = Math.max(preMax+num,curMax);
preMax = tmp;
}
return curMax;
}