题目
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 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
使用最多的题解
// 动态规划
class Solution {
public int rob(int[] nums) {
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(dp[0], nums[1]);
for (int i = 2; i < nums.length; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
return dp[nums.length - 1];
}
}
我的题解,附带详细解释
我觉得题目给出的范围 1 <= nums.length <= 100
,那么就没必要考虑 nums.length=0
这种情况。
直接从 1 开始初始化 dp 数组,有一间和两间屋子的时候最特殊,可以作为 dp 数组初始值。
class Solution {
public int rob(int[] nums) {
// dp[i]
// i代表有几间房屋
// dp[i]就代表能偷到的最大总金额
int[] dp=new int[nums.length+1];
// 有一间房屋,那么就只能偷这么多钱
dp[1]=nums[0];
// 防止只有一间屋子时,dp[2]数组越界
if(nums.length==1){
return dp[1];
}
// 有两间房屋,就在两间房屋里选最大金额的来偷
dp[2]=Math.max(nums[0], nums[1]);
for(int i=3; i<dp.length; i++){
// 有3间及更多房屋时,就考虑是隔一间来偷还是不隔一间
// 举个例子,当有3个房屋时,
// 不隔一间房屋偷,只能偷到第二间房屋的钱
// 隔一件房屋偷,就能偷到第一间房屋和第三间房屋的钱
// 为什么是+=?
// 因为是偷多个房间,所以是累加,即+=
// 为什么是 nums[i-1] ?
// 因为这个 i 是用来遍历dp数组的,而 dp 数组的长度比 nums 数组长 1
// 当有3个屋子时,第3个屋子的钱应该是nums[2],所以要-1
dp[i]+=Math.max(dp[i-1], dp[i-2]+nums[i-1]);
}
return dp[nums.length];
}
}
有点小懵
刚刚我发现,+= 和 = 在两个题解中都可以。。。。纳尼!
哦,因为这是一维循环,所以+= 和 = 作用一样,因为 dp[i] 初始值都为 0 ,要是是二维循环,作用可就不一样了。
举个例子:
背包问题,也是 dp[i] , 但其实它是两个维度,为了减少储存空间,才降为一维的,因此,每一次循环,dp[i] 初始值就不为 0 啦。
写完对动态规划的总结后发现
这也是一维的方式,都一样的,悟了悟了