leetcode-打家劫舍(動態規划)


你是一個專業的小偷,計划偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。
給定一個代表每個房屋存放金額的非負整數數組,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。
示例 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 。
 
這道題的本質相當於在一列數組中取出一個或多個不相鄰數,使其和最大。那么我們對於這類求極值的問題首先考慮動態規划Dynamic Programming來解,我們維護一個一位數組dp,其中dp[i]表示到i位置時不相鄰數能形成的最大和,那么遞推公式怎么寫呢,我們先拿一個簡單的例子來分析一下,比如說nums為{3, 2, 1, 5},那么我們來看我們的dp數組應該是什么樣的,首先dp[0]=3沒啥疑問,再看dp[1]是多少呢,由於3比2大,所以我們搶第一個房子的3,當前房子的2不搶,所以dp[1]=3,那么再來看dp[2],由於不能搶相鄰的,所以我們可以用再前面的一個的dp值加上當前的房間值,和當前房間的前面一個dp值比較,取較大值當做當前dp值,所以我們可以得到遞推公式dp[i] = max(num[i] + dp[i - 2], dp[i - 1]), 由此看出我們需要初始化dp[0]和dp[1],其中dp[0]即為num[0],dp[1]此時應該為max(num[0], num[1]),代碼如下
class Solution {
    public int rob(int[] nums) {
        
      int len=nums.length;
        if(len==0)return 0;
        if(len==1)return nums[0];
int dp[]=new int[len];
        dp[0]=nums[0];dp[1]=Math.max(nums[0],nums[1]);
        for(int i=2;i<len;i++){
            dp[i]=Math.max(dp[i-2]+nums[i],dp[i-1]);
        }
        int k=0;
        for(int i=0;i<len;i++){
            if(dp[i]>dp[k])k=i;
        }
        return dp[k];
    }
}

方法2:分開a,b通過奇偶分別維護一個數, 這樣就可以保證組成最大和的數字不相鄰

class Solution {
    public int rob(int[] nums) {
        
      int len=nums.length;
        if(len==0)return 0;
        if(len==1)return nums[0];
        int a=0,b=0;
        for(int i=0;i<nums.length;i++){
            if(i%2==0){
                a=Math.max(a+nums[i],b);
            }else
                b=Math.max(b+nums[i],a);
        }
        return Math.max(a,b);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM