1. 程式人生 > >【LeetCode & 劍指offer刷題】動態規劃與貪婪法題8:House Robber(系列)

【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]表示包含當前值的最大值 遞迴寫法有點像 34 二叉樹中和為某一值的路徑(112. Path Sum) */ 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