继续打家劫舍
思路
這道題目和198.打家劫舍是差不多的,唯一區(qū)別就是成環(huán)了。
對于一個數(shù)組,成環(huán)的話主要有如下三種情況:
情況一:考慮不包含首尾元素
情況二:考慮包含首元素,不包含尾元素
情況三:考慮包含尾元素,不包含首元素
注意我這里用的是"考慮",例如情況三,雖然是考慮包含尾元素,但不一定要選尾部元素! 對于情況三,取nums[1] 和 nums[3]就是最大的。
而情況二 和 情況三 都包含了情況一了,所以只考慮情況二和情況三就可以了。
代碼如下:
class Solution { public:int rob(vector<int>& nums) {if(nums.size()==0) return 0;if(nums.size()==1) return nums[0];if(nums.size()==2) return max(nums[0],nums[1]);vector<int> dp1(nums.size());//情況二,不考慮尾部元素dp1[0]=nums[0];dp1[1]=max(nums[0],nums[1]);vector<int> dp2(nums.size());//情況三,不考慮首部元素dp2[0]=0;dp2[1]=nums[1];dp2[2]=max(nums[1],nums[2]);for(int ii=2;ii<nums.size()-1;ii++){dp1[ii]=max(dp1[ii-1],dp1[ii-2]+nums[ii]);}for(int ii=3;ii<nums.size();ii++){dp2[ii]=max(dp2[ii-1],dp2[ii-2]+nums[ii]);}return max(dp1[nums.size()-2],dp2[nums.size()-1]);} };抽象化
// 注意注釋中的情況二情況三,以及把198.打家劫舍的代碼抽離出來了 class Solution { public:int rob(vector<int>& nums) {if (nums.size() == 0) return 0;if (nums.size() == 1) return nums[0];int result1 = robRange(nums, 0, nums.size() - 2); // 情況二int result2 = robRange(nums, 1, nums.size() - 1); // 情況三return max(result1, result2);}// 198.打家劫舍的邏輯int robRange(vector<int>& nums, int start, int end) {if (end == start) return nums[start];vector<int> dp(nums.size());dp[start] = nums[start];dp[start + 1] = max(nums[start], nums[start + 1]);for (int i = start + 2; i <= end; i++) {dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);}return dp[end];} };總結(jié)
成環(huán)之后還是難了一些的, 不少題解沒有把“考慮房間”和“偷房間”說清楚。
這就導(dǎo)致會有這樣的困惑:情況三怎么就包含了情況一了呢? 本文圖中最后一間房不能偷啊,偷了一定不是最優(yōu)結(jié)果。
所以本文重點強調(diào)了情況一二三是“考慮”的范圍,而具體房間偷與不偷交給遞推公式去抉擇。
這樣就不難理解情況二和情況三包含了情況一了。
總結(jié)