本系列使用IDEA+LEETCODE EDITOR插件,题目描述统一英文。
题目链接
一、题目描述:
//You are a professional robber planning to rob houses along a street. Each hous
//e has a certain amount of money stashed, the only constraint stopping you from r
//obbing each of them is that adjacent houses have security system connected and i
//t will automatically contact the police if two adjacent houses were broken into
//on the same night.
//
// Given a list of non-negative integers representing the amount of money of eac
//h house, determine the maximum amount of money you can rob tonight without alert
//ing the police.
//
//
// Example 1:
//
//
//Input: nums = [1,2,3,1]
//Output: 4
//Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
// Total amount you can rob = 1 + 3 = 4.
//
//
// Example 2:
//
//
//Input: nums = [2,7,9,3,1]
//Output: 12
//Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5
//(money = 1).
// Total amount you can rob = 2 + 9 + 1 = 12.
//
//
//
// Constraints:
//
//
// 0 <= nums.length <= 100
// 0 <= nums[i] <= 400
二、思路分析:
首先读题,看起来花里胡哨的,总结起来就是文章标题里的数组内非相邻元素最大合问题。这是道M,所以依然还有坑等着你。
题目会迷惑你让你以为只能隔一个抢一个,实际上你隔几个抢都行,只要不相邻。
注意一个思维误区: [1,2,3,4,5],抢了1后如果直接求下一次的最好选择,你会直接抢到5,然后发现才总共6,所以局部最优解绝不是下次抢所有剩余房子中的哪个的结果最大,切记切记。而应该是在抢当前的还是下一个中选择,尽量多抢是核心要求,而这道题的局部最优解是在抢当前和抢下一个中产生的,并不是抢当前和抢剩余所有中最大的那个。
所以能通过题目花里胡哨/复杂的描述总结出核心问题,并且找到可能的坑,这个才是这期的重点内容。
然后直接可以写出一版递归代码:
class Solution {
public int rob(int[] nums) {
return rob(nums,0);
}
int rob(int[] nums,int index){
if(index >= nums.length){
return 0;
}
// 不抢当前直接去下一家和抢当前的然后去下下一家比较
return Math.max(rob(nums,index + 1),nums[index] + rob(nums,index+2));
}
}
一运行,超时了,思考如何优化:
涉及到递归就有一个剪枝问题,从上面代码可知,可以缓存每次index的结果。
优化后时间超过100%。
三、AC 代码:
class Solution {
int[] indexValue;
public int rob(int[] nums) {
indexValue = new int[nums.length];
Arrays.fill(indexValue, -1);
return rob(nums, 0);
}
// 代码超时,思考为什么:只要用了递归,必有的性能优化就是剪枝。缓存index的值
int rob(int[] nums, int index) {
if (index >= nums.length) {
return 0;
}
if (indexValue[index] != -1) {
return indexValue[index];
}
// 不抢当前直接去下一家和抢当前的然后去下下一家比较
int result = Math.max(rob(nums, index + 1), nums[index] + rob(nums, index + 2));
indexValue[index] = result;
return result;
}
}
解答成功:
执行耗时:0 ms,击败了100.00% 的Java用户
内存消耗:36.1 MB,击败了7.86% 的Java用户
四、总结:
- 练习透过花里胡哨或者复杂的问题描述直击核心问题的能力。
- 只要写了递归,就一定要思考如何剪枝,剪枝和递归必然一起出现。
- 弄清什么是真正的局部最优解,比如这道题直接找接下来最大的值就错了,局部最优解是有范围的,找到范围最重要。
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情