【LeetCode & 劍指offer刷題】動態規划與貪婪法題8:House Robber(系列)


【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...)

House Robber(系列)

  House Robber
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and   it will automatically contact the police if two adjacent houses were broken into on the same night .
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight   without alerting the police .
Example 1:
Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
Example 2:
Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
Total amount you can rob = 2 + 9 + 1 = 12.

C++
 
/*
問題:一個竊賊要盜竊一條街上的房子。每個房子里有固定數量的錢,竊賊如果在一個晚上偷了兩個相鄰的房子就會觸發警報,警察就會來抓這個竊賊。那么,怎樣一個盜竊方案能使竊賊拿到的錢最多且不觸發警報。
( 本質相當於在一列數組中取出一個或多個不相鄰數,使其和最大
*/
/*
方法一:動態規划
dp[i]表示到i位置時不相鄰數能形成的最大和
對於某個位置i,可以取也可以不取,
如果取(不能相鄰取,故只能加上前面的前面的dp值),則為dp[i-2] + num[i],如果不取,則為dp[i-1]
所以遞推公式為dp[i] = max(dp[i-2] + num[i], dp[i-1])
*/
class Solution
{
public :
    int rob ( vector < int > & num )
    {
        if ( num . empty ()) return 0 ;
        if ( num . size () == 1 ) return num [ 0 ];
       
        vector < int > dp ( num . size ()); //對於數組類的題,如果i表示下標,0序分析即可,可以不用多開辟一個空間
        dp [0] = num [ 0 ]; //初始化前兩個dp值 
        dp [1] = max ( num [ 0 ], num [ 1 ]);
       
        for ( int i = 2 ; i < num . size (); i ++) //從位置2開始掃描
        {
            dp [i] = max(dp[i-2] + num[i], dp[i-1]);
        }
        return dp . back ();
    }
};
/*
方法二:動態規划,空間的優化
分別維護兩個變量a和b,然后按奇偶分別來更新a和b,這樣就可以保證組成最大和的數字不相鄰
遍歷奇數序列,遍歷偶數序列,交叉比較(每次判斷是否加當前數)
時間復雜度O(n),空間復雜度O(1)
*/
class Solution
{
public :
    int rob ( vector < int >& nums )
    {
        int a = 0 , b = 0 ; //a為偶數累加器,b為奇數累加器
      
        for ( int i = 0 ; i < nums . size (); i ++)
        {
            if ( i % 2 == 0 ) a = max ( a + nums [ i ], b ); //選擇加當前數或者上一個奇數累加器值(此表達式的可以約束相鄰的兩數不會同時取到)
            else b = max ( a , b + nums [ i ]); //選擇加當前數或者上一個偶數累加器值
        }
      
        return max ( a , b );
    }
};
 
213 .   House Robber II
 All houses at this place are arranged in a circle.
Example 1:
Input: [2,3,2]
Output: 3
Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2),
because they are adjacent houses.
Example 2:
Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.

 
/*
問題:打家劫舍2(排成圓圈)
現在房子排成了一個圓圈,則如果搶了第一家,就不能搶最后一家,因為首尾相連了,所以第一家和最后一家只能搶其中的一家,或者都不搶
方法:動態規划
如果我們把第一家和最后一家分別去掉,各算一遍能搶的最大值
然后比較兩個值取其中較大的一個即為所求
*/
class Solution
{
public :
    int rob ( vector < int >& nums )
    {
        if ( nums . empty ()) return 0 ;
        if ( nums . size () == 1 ) return nums [ 0 ];
       
        return max (rob(nums, 0, nums.size() - 1), rob(nums, 1, nums.size()));
    }
   
    int rob ( vector < int > & nums , int left , int right )
    {
        if ( right - left <= 1 )
            return nums [ left ];
       
        vector < int > dp ( right );
        dp [ left ] = nums [ left ]; //初始化前兩個dp值
        dp [ left + 1 ] = max ( nums [ left ], nums [ left + 1 ]);
       
        for ( int i = left + 2 ; i < right ; i ++)
        {
            dp [ i ] = max ( nums [ i ] + dp [ i - 2 ], dp [ i - 1 ]);
        }
       
        return dp . back ();
    }
};
 
337 .   House Robber III
The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that "all houses in this place forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night.
Determine the maximum amount of money the thief can rob tonight without alerting the police.
Example 1:
3
/ \
2 3
\     \
3     1
Maximum amount of money the thief can rob =  3  +  3  +  1  = 7.
 
Example 2:
    3
    / \
  4     5
  / \     \
1 3      1
Maximum amount of money the thief can rob =  4  +  5  = 9.

 
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
/*
問題:打家劫舍3
各房子構成二叉樹(每個房子有且只有一個父結點),不能同時偷兩個直接連接的房子
方法:
res[0]表示不包含當前節點值的最大值,res[1]表示包含當前值的最大值
*/
class Solution
{
public :
    int rob ( TreeNode * root )
    {
        vector < int > res = dfs ( root ); //從根結點開始遞歸遍歷
        return max ( res [ 0 ], res [ 1 ]); //返回包含或不包含根結點時的最大值
    }
    vector < int > dfs ( TreeNode * root )
    {
        if (! root ) //空結點時,返回0
            return vector < int >( 2 );
       
        vector < int > left = dfs ( root -> left ); //處理左子樹
        vector < int > right = dfs ( root -> right ); //處理右子樹
        vector < int > res ( 2 );
       
        //處理根結點
        res [ 0 ] = max ( left [ 0 ], left [ 1 ]) + max ( right [ 0 ], right [ 1 ]); //不包含根結點的情況,則左結點和右結點可以包含也可以不包含
        res [ 1 ] = left [ 0 ] + right [ 0 ] + root -> val ; //包含根結點的情況,則不能包含左結點和右結點
        return res ;
    }
};
213.   House Robber II
 

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com