打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
解题思路
这是一个经典的动态规划问题,可以使用动态规划来解决。定义一个数组 dp, 其中 dp[i] 表示偷窃前 i 个房屋能够获得的最高金额。
- 1、对于每间房屋,小偷有两种选择:偷当前房屋或者不偷当前房屋。
- 2、如果选择偷第 i 个房屋,则不能偷第 i-1 个房屋,因此偷窃金额为 nums[i] 加上前 i-2 个房屋能够获得的最高金额 dp[i-2]。
- 3、如果选择不偷第 i 个房屋,则偷窃金额为前 i-1 个房屋能够获得的最高金额 dp[i-1]。
因此,动态规划方程如下: -
边界条件为:dp[i] = max(dp[i-1], dp[i-2] + nums[i]),其中 2 <= i < n
-
dp[0] = nums[0],只有一个房屋时能够获得的最高金额为该房屋金额
-
dp[1] = max(nums[0], nums[1]),只有两个房屋时能够获得的最高金额为其中金额较大的房屋
- 4、最终返回 dp[n-1] 即可得到最大的偷窃金额。
Java实现
public class HouseRobber {
public int rob(int[] nums) {
if (nums == null || nums.length == 0) return 0;
if (nums.length == 1) return nums[0];
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];
}
public static void main(String[] args) {
HouseRobber robber = new HouseRobber();
int[] nums = {1, 2, 3, 1};
System.out.println("Maximum amount stolen: " + robber.rob(nums)); // Output: 4
}
}
时间空间复杂度
-
时间复杂度:遍历一次数组,时间复杂度为O(n),其中n为房屋的数量。
-
空间复杂度:使用了长度为n的数组dp,空间复杂度为O(n)。