1. 程式人生 > >LeetCode House Robber題解

LeetCode 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 andit 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 tonightwithout alerting the police.

        題意大致翻譯如下:假設你是一個職業盜賊,準備對一條街上的住戶下手。每戶人家存放了不同數量的現金,你不能同時盜取相鄰的兩戶人家,因為這樣會產生警報你就悲劇了。給你一個存放各戶人家金錢數量的列表,在保證不被抓住的情況下儘量獲得更多金錢。

        這是一個明顯的動態規劃的題目,解題的關鍵在於找到當前獲得最大金錢數與之前可以獲得的金錢數之間的關係。在列表長度小於4的情況下獲得最大現金的情形很容易分析,在超過4的情況下,我們需要做一個判斷。由於不能取相鄰的值,所以當前可以獲得最大值或者是前一位的最大值,或者是更前位置的最大值加上當前位置的數值,關鍵在於之前的位置是當前位置之前的第幾個?這裡舉一個test case說明 { 4, 1, 2, 7, 6, 3, 1},這裡從5這個值開始分析,之前四個位置分別可以獲得的最大值為4,4,6,11。我們看如果第五個位置要取最大值,可以一下情形,取位置4的最大值11, 取位置3的最大值6加本位置的6,取位置2的最大值4加6,取位置1的最大值4加6。當然如果之前還有值,我們還可以再往前取最大值在加當前位置的值。可是我們注意到,取位置3的最大值6是由位置1和位置3的最大值合取的,所以位置1的最大值已經被包含進位置3的最大值,也即是取之前最大值與當前最大值最大間隔2,再往前取就是已經重複了的。假設某一位置的最大值為most(n),某一位置的金錢數為cash(n),由此我們得出如下動態規劃方程,

most(n) = max(most(n-1), most(n-2)+cash(n), most(n-3)+cash(n))。有了這個方程,程式碼就很容易出來了,可以遞迴,也可以迭代。首先看遞迴程式碼

// 過載的max函式
int max(int a, int b)
{
	return a > b ? a : b;
}
 
// 過載的max函式
int max(int a, int b, int c)
{
	if (a >= b && a >= c)
		return a;

	if (b >= a && b >= c)
		return b;

	if (c >= a && c >= b)
		return c;
}

int robMax(vector<int> &num, int index)
{
	if (index == 0)
		return num[0];
	else if (index == 1)
		return max(num[0], num[1]);
	else if (index == 2)
		return (max(num[0] + num[2], num[1]));
	else if (index > 2)
		return max(robMax(num, index - 3) + num[index] , robMax(num, index - 2) + num[index], robMax(num, index - 1));

}

int rob(vector<int> &num) {

	if (num.empty())
		return 0;

	int size = num.size();
	return robMax(num, size - 1);

}
不過由於遞迴巢狀太深,在執行大量資料時就超時了。所以還是走迭代的路,下面看迭代的程式碼

int rob(vector<int> &num) {

	if (num.empty())
	    return 0;

	int size = num.size();
	if (size == 1)
		return num[0];
	else if (size == 2)
		return max(num[0] , num[1]);
	else if (size == 3)
		return max(num[0] + num[2] ,num[1]);
	else
	{
		
		int temp = 0;
		num[2] = max(num[0] + num[2], num[1]);
		for (size_t i = 3; i < size; ++i)
		{
			temp = num[i];
                        // 在每個位置上儲存當前能獲得的最大金錢數
                        num[i] = max(num[i - 3] + temp, num[i - 2] + temp, num[i - 1]);
			
		}
	}
	
	return num[size -1];

}
        這裡的max函式和之前相同,就不列出了,最後程式碼Accepted,用時3ms。

        這篇文章是筆者第一次發原創,限於水平所限難免有不足支出,歡迎批評指正!