【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;
	}
};

你可能感兴趣的:(【魂】算法,c++,leetcode,动态规划)