题目描述:
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
示例 1:
输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2:
输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 3:
输入:nums = [1,2,3]
输出:3
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 1000
思路:
看上去跟昨天的打家劫舍一模一样,就是多了一个限制条件,这些房子都围成了一个圈,这就意味着,最后一个房子跟以一个房子也算相邻了。也就是说,在考虑最后一个房子选不选的时候,我们还需要考虑这个时候第一个房子选了没有,如果第一个房子选了,那么最后一个房子就一定不能选。可是我们怎么知道第一个房子到底选了没有呢?
于是问题就可以简化成两个方向去思考:
1.第一个房子一定选
2.第一个房子一定不选
所有选房子的方案一定可以归结为这两类,一个是包含第一个,一个是不包含。
再对这两个方案求一个max就可以了。
于是乎,我们开两个数组,一个是存方案一的状态,一个是存方案二的状态。
需要注意的就是边界条件。
对于方案一来说,一定选第一个房子,也就意味着:
f[0]=nums[0]且f[1]=nums[0](此时第二个房子一定不能选所以前2个房子的钱最多还是nums[0]),
对于最后一个房子来说,既然第一个房子一定选,那么最后一个房子就不能选,此时f[i]=f[i-1].
对于方案二:
f2[0]=0且f2[1]=nums[1].对于最后一个房子,可以选也可以不选,不冲突。
代码:
#define _CRT_SECURE_NO_WARNINGS 1 class Solution { public: int rob(vector<int>& nums) { int f[10000] = { 0 };//拿第一家的钱 int f2[10000] = { 0 };//不拿第一家 int len = nums.size(); if (len == 1)return nums[0];//只有一栋房子直接退 // nums.push_back(nums[0]); f[0] = nums[0];//拿第一家 f2[0] = 0;//不拿 f[1] = f[0]; f2[1] = nums[1]; for (int i = 2; i < len; i++) { // f[i]=max(f[i-1],f[i-2]+nums[i]-f[0]); if (i == len - 1) { f[i] = f[i - 1];//此时不能拿最后一个房子,座椅 f2[i] = max(f2[i - 1], f2[i - 2] + nums[i]);//由于不拿第一家房子,最后一家可拿可不拿 } else { f[i] = max(f[i - 1], f[i - 2] + nums[i]); f2[i] = max(f2[i - 1], f2[i - 2] + nums[i]); } } return max(f[len - 1], f2[len - 1]);//两种方案取最大 } };