### 【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位置時不相鄰數能形成的最大和

*/
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 ();
}
};
/*

*/
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),
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.

/*

*/
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) {}
* };
*/
/*

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