LeetCode-198. 打家劫舍
阿新 • • 發佈:2019-02-06
題目描述:你是一個專業的強盜,計劃搶劫沿街的房屋。每間房都藏有一定的現金,阻止你搶劫他們的唯一的制約因素就是相鄰的房屋有保安系統連線,如果兩間相鄰的房屋在同一晚上被闖入,它會自動聯絡警方。
給定一個代表每個房屋的金額的非負整數列表,確定你可以在沒有提醒警方的情況下搶劫的最高金額。
- 暴力搜尋方法
思路:文中給出不能連續搶兩家,因此假設從最後一個房屋開始搶,最後一個房屋為index。將原問題分割成子問題,子問題的最優決策可以匯出原問題的最優決策。現有兩種可能情況,當前房屋搶和當前房屋不搶。若當前房屋搶,則下一房屋不能搶;若當前房屋不搶,則下一房屋可搶;選出這兩種情況的最大值,遞迴執行,直到index<0。
public int solve(int index, int[] nums){
if(index < 0){
return 0;
}
int max = Math.max(nums[index] + solve(index - 2, nums), solve(index - 1, nums));
return max;
}
public int rob(int[] nums) {
return solve(nums.length-1, nums);
}
此種暴力方法在執行第56個測試用例時,超出時間限制。
假設我們搶n-1家,那麼接下來的執行方案:
n-1 ->(n-3, n-4, n-5)
假設我們搶n-2家,那麼接下來的方案為:
n-2 ->(n-4, n-5)
那麼我的兩種決策方式只是影響能不能搶n-3,在n-3之後都是隨便搶的;通過觀察上述兩種方案,我們發現了n-4,n-5被重複計算。因此,每一家都有兩種可能可能,搶或者不搶。則該演算法的時間複雜度為:。
為了避免上述的重複計算,我們初始化一個數組來記錄所有記錄為-1,如果當前index被算過,就記錄下來。因此,每次判斷該屋搶還是不搶後,都會得到一個index值。這就是去冗餘
因此,我們考慮使用動態規劃,設定result[]陣列記錄搶奪該房屋可能的最大收益。
自頂向下解法
class Solution {
public static int[] result;
public int solve(int index, int[] nums){
if(index < 0){
return 0;
}
if(result[index] >= 0){
return result[index];
}
result[index] = Math.max(nums[index] + solve(index-2 , nums), solve(index-1, nums));
return result[index];
}
public int rob(int[] nums) {
result = new int[nums.length];
for(int i=0; i < result.length; i++){
result[i]=-1;
}
return solve(nums.length-1, nums);
}
}
對於每個房屋我們都算了一次,那麼時間複雜度為
自底向上解法
public int rob(int[] nums) {
if (nums.length == 0){
return 0;
}
if (nums.length == 1){
return nums[0];
}
if (nums.length == 2){
return Math.max(nums[0], nums[1]);
}
int[] result = new int[nums.length];
result[0] = nums[0];
result[1] = Math.max(nums[0], nums[1]);
for(int index=2; index < result.length; index++){
result[index] = Math.max(nums[index] + result[index-2], result[index -1]);
}
return result[nums.length -1];
}
}
自底向上,編碼簡單,遞推(自頂向下為遞迴)。既然自底向上不需要遞迴,那麼就不需要solve函數了。我們只要處理好邊界條件,然後計算即可。