本系列所选题目均来自力扣或者牛客网站. 所选题目主要是以其中的简单题为主, 中等题为辅, 包含少数困难题(原因是: 本人目前能力还不够~ ). 开展这个系列的目的是督促自己, 在暑假的时间里也要保持有一定的刷题量, 拒绝摆烂~
话不多说, 直接开刷~~ 今天两道题目都是最经典的动态规划题目.
打家劫舍
题目描述: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
- 示例:
输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
解题思路:
(1) 动态规划算法是一种空间换取时间的算法, 因为它需要有一个新的数组来存储原数组中每个元素对应的计算结果, 当然, 动态规划算法最重要的就是状态转移方程.
(2) 对于第一个元素, 我们选择偷是有利的, 所以直接照搬原来的值; 对于第二个元素, 我们只需跟第一个元素进行比较即可, 谁大就填入谁的值; 以上的两种情况是边界条件, 往后的其他元素, 都要判断要偷还是不偷: 假如偷的话, 那么可以判定上个房间一定是不偷的, 所以就需要将上上个房间偷来的金钱总额加上本房间偷到的金钱; 而如果不偷的话, 那么目前的金钱总额还是停留在偷上个房间后的金钱总额. 这时候我们就可以通过两个金钱总额的多少来判断是否要偷这个房间.
(3) 所以就有下面的这个状态转移方程:
array[i] = Math.max(array[i-1], array[i-2] + nums[i])
实现代码:
class Solution {
public int rob(int[] nums) {
int len = nums.length;
int[] array=new int[len];
array[0] = nums[0];
for(int i = 1; i < len; i++){
if(i == 1){
array[i] = Math.max(nums[i], nums[i-1]);
}else{
array[i] = Math.max(array[i-1], array[i-2] + nums[i]);
}
}
return array[len-1];
}
}
打家劫舍II
题目描述: 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
- 示例:
输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
解题思路:
(1) 这道题是上面那题的进阶版本, 特殊值处就在于这些房间变成是首尾相连的围在一起了. 虽然题目变复杂了,但是核心代码部分还是和上面差不多的.
(2) 本题我们抓住重点 — 偷第一个房间就不能偷最后一个房间; 偷最后一个房间就不能偷第一个房间. 所以, 我们就可以把原来的这些房间分成两部分(也就是以上这两种情况: 从第一个房间偷到倒数第二个房间 & 从第二个房间偷到最后一个房间), 然后来判断这两种情况最后偷到的金钱总额谁多, 取大值即可.
(3) 其中, 上面两种情况偷的过程就是之前的代码, 直接拎出来调用这个方法即可.
(4) 但是但在执行这一行的时候会报错: Arrays.copyOfRange(nums, 0, len-1)
, 原因是 len 的值可能是1, 这时候再在前面排除这种情况之后, 也就大功告成了.
注意: copyOfRange
方法在截取数组的时候是左闭右开的截法!
实现代码:
class Solution {
public int rob(int[] nums) {
int len = nums.length;
if(len == 1){
return nums[0];
}
int[] array = Arrays.copyOfRange(nums, 0, len-1);
int[] brrby = Arrays.copyOfRange(nums, 1, len);
return Math.max(robValue(array), robValue(brrby));
}
public int robValue(int[] nums){
int len = nums.length;
int[] array = new int[len];
array[0] = nums[0];
for(int i = 1; i < len; i++){
if(i == 1){
array[i] = Math.max(nums[0], nums[1]);
}else{
array[i] = Math.max(array[i-1], array[i-2] + nums[i]);
}
}
return array[len-1];
}
}