Leetcode DP1 打家劫舍

題目

你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。

給定一個代表每個房屋存放金額的非負整數數組,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。

示例 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 。

問題分解

  1. subproblem:簡單來說就是四個房子{1,2,3,4},偷的方式有14,13,24三種。

  2. guess:小偷目前偷到第i家,手中的錢有三種情況,第i家偷不偷取決于:
    a. 第i-1家沒有偷,可以偷,偷了之后手中的錢為S_{i-2}+s_{i} (24)
    b. 第i-1家偷了,直接手中的錢維持不變為S_{i-1} (13)
    c. 第i-1家偷了,但是偷第i家的話錢會變多,把第i-1家的錢放回去偷第i家的,錢變為S_{i-2}+s_{i}S_{i-3}S_{i-2}是等價的,因為第i-2家沒有偷 (14)
    可以總結為:小偷到了第i家,比較a,b,c三個條件來做出選擇,實則就是比較S_{i-2}+s_{i}S_{i-1}的大小,因為條件c最后是和條件a一樣的,也就是第i-1家沒有偷,而對于subproblem中的第1,2,3棟房子,它們的金額應該分別對應S_{i-3},S_{i-2},S_{i-1}

3.relate subproblems and solutions(always using recursion):用prefix來做,維護小偷的記錄本dp,記錄到了第i家的時候錢包里的錢S_i,看完第i+1家的錢之后,比較abc三個條件,來記錄S_{i+1}

4.bottom up

5.solve the original problem

維護一個dp列表,進行一個循環即可,時間復雜度為O(n),一開始用recursive做,太慢了,且沒有必要,因為每一次循環都只關注四個房子(實則是三個),三個記賬數目上而已。

代碼實現

C++

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size()==0)
        {
            return 0;
        }
        if(nums.size()==1)
        {
            return nums[0];
        }
        vector<int> dp(nums.size());
        dp[0] = nums[0];
        if(nums[0]<nums[1]){
            dp[1]=nums[1];
        }
        else
        {
            dp[1]=nums[0];
        }
        for(int i =2;i<nums.size();++i)
        {
            if(nums[i]+dp[i-2]>dp[i-1]){
                dp[i] = nums[i]+dp[i-2];
            }
            else
            {
                dp[i]= dp[i-1];
            }
        }
        return dp[nums.size()-1];
    }
};

python

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        
        if nums==[]:
            return 0
        if len(nums)==1:
            return max(nums)
        dp = [0]*len(nums)
        dp[0] = nums[0]
        dp[1] = max(nums[1],nums[0])
        for i in range(2,len(nums)):
            dp[i] = max(dp[i-1],dp[i-2]+nums[i])
            
        return dp[len(nums)-1]

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 近期的目標是時間管理,所以今天我的咖啡冥想內容是 1.素顏上班,堅持對每個人微笑,也收獲了許多微笑,原來笑...
    96291458eb20閱讀 132評論 0 0
  • 第五章 [原文] 天地不仁,以萬物為芻狗;圣人不仁,以百姓為芻狗。天地之間,其猶橐龠乎?虛而不屈,動而俞出。多聞數...
    道形圖閱讀 295評論 6 14
  • 今天覺得好熱 不動都冒汗! 本來想著舒坦懶散一天 可摸摸最近吃夜宵圓滾滾的肚子 還是下定決心 拿起手機 預約了兩節...
    Vivian_dh閱讀 224評論 2 4
  • 消極的時候總會質疑自己,我不知道普普通通的生活著,大學畢業是怎樣?我知道,結果總是沒那么差,只是沒有顆心接受,沒有...
    Freakyboy閱讀 428評論 1 0