【LeetCode】213. 打家劫舍 II

解題思路

參考自
@jyd

環狀排列意味着第一個房子和最後一個房子只能選擇一個偷竊,因此可以把此環裝排列房間問題簡化成爲兩個單排排列房間子問題:
1.在不偷竊第一個房子的情況下(即nums[1:]),最大金額是p1;
2.在不偷竊最後一個房子的情況下(即nums[:n-1]),最大金額是p2;

綜合偷竊最大金額:爲以上情況的較大值,即max(p1,p2);
因此問題轉換爲解決兩個單排排列房間問題。
自己分別寫了兩份代碼,第一份是直接利用198.打家劫舍的版代碼複製了其中一些內容完成的。時間複雜度O(n),空間複雜度O(1)
第二份代碼,參考了krahets的題解進行了優化和修改,
時間複雜度O(n),空間複雜度O(1)

代碼

未簡化版代碼

dp[i]:表示爲盜竊到第i個房間獲得的最大值
由於不可以在相鄰的房屋闖入,所以在當前位置i房屋可盜竊的最大值,要麼就是i-1房屋可盜竊的最大值,要麼就是
i-2房屋可盜竊的最大值加上當前房屋的值,二者之前取最大值
dp[i] = max(dp[i - 1], nums[i] + dp[i - 2]);


class Solution {
public:
	int rob(vector<int>& nums) {
		int sizeNums = nums.size();
		//對size==0、1、2時的特殊判斷
		if (sizeNums == 0||sizeNums==1||sizeNums==2) return 0;
		//dp數組
		vector<int> dp(nums.size() + 1);
		//邊界值
		dp[1] = nums[0];//第1個房屋可盜竊的最大值
		dp[2] = max(nums[1], dp[1]);//第2個房屋可盜竊的最大值
		//狀態轉移
		//偷1房間不偷n房間
		for (int i = 3; i < nums.size() + 1; i++)
		{
			if (i != nums.size())
				dp[i] = max(dp[i - 1], nums[i - 1] + dp[i - 2]);
			else dp[i] = dp[i - 1];
		}
		int maxOne = dp[nums.size()];
		//偷n房間,不偷1房間
		dp[2] = nums[1];
		dp[3] = max(nums[2], dp[2]);
		for (int i = 4; i < nums.size() + 1; i++)
		{
			dp[i] = max(dp[i - 1], nums[i - 1] + dp[i - 2]);
		}
		return max(maxOne, dp[nums.size()]);
	}
};

簡化版代碼

dp[i]=max(dp[i-2]+num[i],dp[i-1])
pre對應的是前dp[i-2];
cur對應dp[i-1],也對應着dp[i]
在該式cur=max(pre + num, cur)中,cur在左側充當dp[i],在右側充當dp[i-1]

class Solution {
public:
	int rob(vector<int>& nums) {
		if (nums.size() == 0) return 0;
		if (nums.size() == 1) return nums[0];
		return max(myRob(vector<int>(nums.begin(), nums.end() - 1)), myRob(vector<int>(nums.begin() + 1, nums.end())));
	}
private:
	int myRob(vector<int> nums) {
		int pre = 0, cur = 0, tmp;
		for (auto num : nums)
		{
			tmp = cur;
			cur = max(pre + num, cur);
			pre = tmp;
		}
		return cur;
	}
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章