本题是动态规划问题。
第一步,明确并理解dp数组以及下标的含义
dp[i]表示从第0号房间一直到第i号房间(包含第i号房间)可以偷到的最大金额,具体怎么偷这里不考虑,第i+1号及之后的房间也不考虑。换句话说,dp[i]也就是只考虑[0,i]号房间,无论怎么偷可以偷到的最大金额。
按照这个定义,dp[n-1]就是答案。需要注意的是,dp[i]一定能求到值,不代表一定是偷了第i号房间才求得dp[i]。
第二步,明确并理解递推公式
考虑第i号房间,只有两种可能,偷或者不偷。
偷第i号房间,则第i-1号房间肯定不能偷,此时能获得的总金额为dp[i] = dp[i-2] + nums[i]。
不偷第i号房间,此时dp[i]应该等于dp[i-1]。
第三步,理解dp数组如何初始化
dp[0]应该初始化为第0号房间的金额。因为只有一间房的时候,能偷到的最大金额显然就是把它偷了。
dp[1],含义是从第0号房间和第1号房间偷,能偷到的最大金额。由于相邻的房间不能都偷,所以dp[1]= max(nums[0],numd[1]);
i>=2的dp[i]可以不初始化,或者说无论初始化为多大都没关系,因为dp[i]只和dp[i-1],dp[i-2],nums[i]有关系。
第四步,理解遍历顺序
因为dp[i]依赖于它前面的dp[i-1]和dp[i-2],所以i的遍历顺序肯定要从小到大。
代码
按照上面的思路,先初始化dp[0]和dp[1],再让i从2开始遍历,含义更加明确,代码更好理解,如下所示:
class Solution {
public:int rob(vector<int>& nums) {int n = nums.size();//dp[i]表示从第0号房间一直到第i号房间(包含第i号房间)可以偷到的最大金额。//按照这个定义,dp[n-1]就是答案vector<int> dp(n);dp[0] = nums[0];if(n < 2)return dp[0];dp[1] = max(nums[0],nums[1]);for(int i = 2;i < n;i++){//偷第i号房间int temp1 = dp[i-2] + nums[i];//不偷第i号房间int temp2 = dp[i-1];dp[i] = max(temp1,temp2);}return dp[n-1];}
};
但实际上,也可以不初始化让i从0开始遍历,代码如下所示:
class Solution {
public:int rob(vector<int>& nums) {int n = nums.size();//dp[i]表示从第0号房间一直到第i号房间(包含第i号房间)可以偷到的最大金额。//按照这个定义,dp[n-1]就是答案vector<int> dp(n);for(int i = 0;i < n;i++){//偷第i号房间int temp1 = (i >= 2 ? dp[i-2]:0) + nums[i];//不偷第i号房间int temp2 = i >= 1 ? dp[i-1]:0;dp[i] = max(temp1,temp2);}return dp[n-1];}
};