【LeetCode & 劍指offer刷題】動態規劃與貪婪法題8:House Robber(系列)
阿新 • • 發佈:2019-01-06
【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 andC++ /* 問題:一個竊賊要盜竊一條街上的房子。每個房子裡有固定數量的錢,竊賊如果在一個晚上偷了兩個相鄰的房子就會觸發警報,警察就會來抓這個竊賊。那麼,怎樣一個盜竊方案能使竊賊拿到的錢最多且不觸發警報。 ( 本質相當於在一列陣列中取出一個或多個不相鄰數,使其和最大) */ /* 方法一:動態規劃 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