1. 题目
读题
https://leetcode.cn/problems/house-robber/
考查点
这道题的考查点是动态规划的基本思想和应用,
- 即如何将一个复杂的问题分解成更小的子问题,
- 如何找到问题的状态和状态转移方程,
- 如何确定问题的边界条件和初始值,
- 以及如何用代码来实现动态规划的算法。
2. 解法
思路
一个可能的解决方案是使用一个一维数组dp来存储每个房屋的最大收益,
dp[i]表示从第0个房屋到第i个房屋能够偷窃的最大金额。
那么对于每个房屋,
我们有两种选择:偷或者不偷。
如果我们偷第i个房屋,那么我们不能偷第i-1个房屋,所以dp[i] = dp[i-2] + nums[i]。
如果我们不偷第i个房屋,那么我们可以偷第i-1个房屋,所以dp[i] = dp[i-1]。
我们要取这两种情况的较大值,所以dp[i] = max(dp[i-1], dp[i-2] + nums[i])。
代码逻辑
我可以用以下的步骤来描述代码的逻辑:
- 首先,我检查输入的数组是否为空或者长度为0,如果是,就直接返回0,因为没有房屋可以偷窃。
- 其次,我检查输入的数组的长度是否为1,如果是,就直接返回数组的第一个元素,因为只有一间房屋可以偷窃。
- 然后,我创建一个一维数组dp来存储每个房屋的最大收益,数组的长度和输入的数组相同。我初始化dp[0]为nums[0],dp[1]为nums[0]和nums[1]中的较大值。
- 接着,我从第2个房屋开始遍历输入的数组,对于每个房屋,我用状态转移方程来更新dp[i],即dp[i] = max(dp[i-1], dp[i-2] + nums[i])。
- 最后,我返回dp[n-1]作为最终结果,其中n是输入数组的长度。
具体实现
class Solution { public int rob(int[] nums) { // 边界条件 if (nums == null || nums.length == 0) { return 0; } if (nums.length == 1) { return nums[0]; } // 创建dp数组 int n = nums.length; int[] dp = new int[n]; // 初始化 dp[0] = nums[0]; dp[1] = Math.max(nums[0], nums[1]); // 遍历 for (int i = 2; i < n; i++) { // 状态转移方程 dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i]); } // 返回结果 return dp[n-1]; } }
3. 总结