Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
题目:一个小偷准备晚上偷东西,每家都会有一定数量的现金,但如果同时偷盗相邻的两家,则会发生报警。要求设计一个方法能使得小偷在一晚上偷到的现金最多。
解题思路
本题唯一的限制就是不能偷盗连续两家的,我们可以先使用几个小数据进行模拟。假设只有一家,则最大偷盗的就是那家的现金。假设只有两家,则会偷盗两家现金较多的那家。如果有三家,则会比较第一家和第三家的现金和与第二家哪个大,选择大的偷。那么如果有四家呢?此时的情况就变成偷盗以下情况最大的:
- 第一家和第三家
- 第二家和第四家
- 第一家和第四家
因此如果屋子的数量大于3
,则我们可以使用动态规划来获取可偷盗的最大现金,我们首先假设如果存在i
家屋子,则第i
家的现金必须偷,此时状态转移方程dp[i]
的含义就是如果确定偷当前屋子能最多偷多少。状态转移方程的更新为:
可得如下代码:
public int rob(int[] nums) {
// dp含义 dp[i]表示如果确定偷当前屋子能最多偷多少
if(nums==null||nums.length==0) return 0;
if(nums.length==1) return nums[0];
if(nums.length==2) return Math.max(nums[0], nums[1]);
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = nums[1];
dp[2] = nums[0] + nums[2];
int maxRob = Math.max(dp[1], dp[2]);
for(int i=3;i<nums.length;i++){
dp[i] = Math.max(dp[i-2], dp[i-3]) + nums[i];
}
for(int value:dp){
maxRob = Math.max(value, maxRob);
}
return maxRob;
}
上述代码时间复杂度和空间复杂度都是。
可否换一种思路,题目要的是当有n间屋子时,所能偷的最大现金数量。那么我们是否可以直接定义动态转移方程的含义dp[i]
就是当存在i
间屋子时所能偷盗的最大现金数量,此时动态转移方程的更新就变为:
可得如下代码:
public int rob2(int[] nums) {
// dp的含义 dp[i]表示当有i间屋子时可偷最大数值
if(nums==null||nums.length==0) return 0;
if(nums.length==1) return nums[0];
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for(int i=2;i<nums.length;i++){
dp[i] = Math.max(dp[i-2] + nums[i] , dp[i-1]);
}
return dp[nums.length-1];
}
代码的时间复杂度和空间复杂度还是。