力扣198题---打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你不触动警报装置的情况下,一夜之内能够偷窃到的最高金额。
示例1: 输入:[1,2,3,1] 输出:4
解释:偷窃1号房屋(金额=1),然后偷窃3号房屋(金额=3)。偷窃到的最高金额=1+3=4。
示例2: 输入:[2,7,9,3,1] 输出:12
解释:偷窃1号房屋(金额=2),偷窃3号房屋(金额=9),接着偷窃5号房屋(金额=1)。偷窃到的最高金额=2+9+1=12。
提示:
1<=nums.length<=100
0<=nums[i]<=400
考虑到每间房屋的最高总金额只和该房屋的前两间房屋的最高总金额相关,因此可以使用滚动数组,在每个时刻只需要存储前两间房屋的最高总金额。
代码如下:
public class Main {
public static void main(String[] args) {
int[] nums = {2, 7, 9, 3, 1};
int x = new Main().rob(nums);
System.out.println(x);
}
public int rob(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
if (n == 1) {
return nums[0];
}
int first = nums[0];
int second = Math.max(nums[0], nums[1]);
for (int i = 2; i < n; i++) {
int temp = second;
second = Math.max(first + nums[i], second);
first = temp;
}
return second;
}
}
输出:12
动态规划代码这样写:
public int rob(int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
int[] dp = new int[n + 1];
dp[0] = 0;
dp[1] = nums[0];
for (int k = 2; k <= n; k++) {
dp[k] = Math.max(dp[k - 1], nums[k - 1] + dp[k - 2]);
}
return dp[n];
}
空间复杂度优化后的代码:
public int rob(int[] nums) {
int count = 0;
int max = 0;
// 每次循环,计算“偷到当前房子为止的最大金额”
for (int i : nums) {
// 循环开始时,max 表示 dp[k-1],count 表示 dp[k-2]
// dp[k] = max{ dp[k-1], dp[k-2] + i }
int temp = Math.max(max, count + i);
count = max;
max = temp;
// 循环结束时,max 表示 dp[k],count 表示 dp[k-1]
}
return max;
}
更简洁的代码:
public int rob(int[] nums) {
int count = 0, max = 0, tmp;
for (int num : nums) {
tmp = max;
max = Math.max(count + num, max);
count = tmp;
}
return max;
}