相比LeetCode 198. House Robber, 由于题目将整个房子变成了一个环形,我们在此就多增加了一维k, 用来专门标识是否取nums[0].
应用动态规划,构造数组dp[nums.size()][2][2], 对于dp[i][j][k],
j=0时不取nums[i], j=1时取nums[i];
k=0时不取nums[0], k=1时取nums[0].
所以dp[i][0][0]即代表,在不去nums[i]和nums[0]的情况下,从nums[0, ..., i]中取得的最大值。
初始化:
// for stage-0
dp[0][1][1] = nums[0];
// for stage-1
dp[1][0][1] = nums[0];
dp[1][1][0] = nums[1];
注意到dp[0][0][1]和dp[1][1][1]都是不合法的特殊情况:如对于dp[1][1][1], 我们不可能同时取第0个和第1个元素(房子里的财产),所以我们将它的值赋为0, 不进行特殊的初始化。
代码:
class Solution
{
public:
int rob(vector<int>& nums)
{
if (nums.empty())
{
return 0;
} else if (nums.size() == 1)
{
return nums[0];
} else if (nums.size() == 2)
{
return max(nums[0], nums[1]);
}
// i: nums index, j: self taken or not, k: nums[0] taken or not
vector<vector<vector<int>>> dp(nums.size(), vector<vector<int>>(2, vector<int>(2, 0)));
// for stage-0
dp[0][1][1] = nums[0];
// for stage-1
dp[1][0][1] = nums[0];
dp[1][1][0] = nums[1];
for (size_t i = 2; i < nums.size(); ++ i)
{
dp[i][0][0] = max(dp[i-1][0][0], dp[i-1][1][0]);
dp[i][0][1] = max(dp[i-1][0][1], dp[i-1][1][1]);
dp[i][1][0] = dp[i-1][0][0] + nums[i];
dp[i][1][1] = dp[i-1][0][1] + nums[i];
}
return max(max(dp[nums.size()-1][0][0], dp[nums.size()-1][0][1]),
dp[nums.size()-1][1][0]);
}
};