【LeetCode-198】打家劫舍(回溯&动归)

目录

解法1:记忆回溯

代码实现

解法2:动态规划

代码实现


题目链接

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

  • 示例 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 。

提示:

  • 0 <= nums.length <= 100

  • 0 <= nums[i] <= 400

解法1:记忆回溯

这个题我们第一眼看去,感觉回溯法可以做,每一次都遍历后面第二个数据。但是这样的后果就是会超时,所以想到使用记忆法来记住已经遍历过的位置的最大值,后面直接返回下一个位置的最大值。

代码实现
java 复制代码
int max_sum = 0;
int[] memo;
public int rob(int[] nums) {
    if (nums.length == 1) return nums[0];
    if (nums.length > 3 && nums[0] == 0 && nums[1] == 0&& nums[2] == 0) return 0;
    memo = new int[nums.length];
    backTracking(0, nums);
    return max_sum;
}
​
​
int backTracking(int index, int[] nums) {
    // 超过了nums的大小就返回0
    if (index >= nums.length) {
        return 0;
    }
    // 等于nums的大小就返回最后的值
    if (index == nums.length-1) {
        return nums[nums.length-1];
    }
    // 如果已经递归过的位置则直接返回值
    if (memo[index] != 0) {
        return memo[index];
    }
​
    int next_max =  0;
    for (int i = index; i < nums.length; i++) {
        int sum = backTracking(i + 2, nums) + nums[i];
        next_max = Math.max(next_max, sum);
    }
    memo[index] = next_max;
    max_sum = Math.max(next_max, max_sum);
​
    return memo[index];
}
​

解法2:动态规划

仔细一想,当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。

所以这里就更感觉到,当前状态和前面状态会有一种依赖关系,那么这种依赖关系都是动规的递推公式。

当然以上是大概思路,打家劫舍是dp解决的经典问题,接下来我们来动规分析如下:

  1. 确定dp数组(dp table)以及下标的含义

dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]

  1. 定递推公式

决定dp[i]的因素就是第i房间偷还是不偷。

如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i] ,即:第i-1房一定是不考虑的,找出 下标i-2(包括i-2)以内的房屋,最多可以偷窃的金额为dp[i-2] 加上第i房间偷到的钱。

如果不偷第i房间,那么dp[i] = dp[i - 1],即考 虑i-1房,(注意这里是考虑,并不是一定要偷i-1房,这是很多同学容易混淆的点

然后dp[i]取最大值,即dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);

  1. dp数组如何初始化

从递推公式dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);可以看出,递推公式的基础就是dp[0] 和 dp[1]

从dp[i]的定义上来讲,dp[0] 一定是0,dp[1]就是nums[0]

代码如下:

java 复制代码
int[] dp = new int[nums.length]
dp[0] = 0;
dp[1] = nums[0]
  1. 确定遍历顺序

dp[i] 是根据dp[i - 2] 和 dp[i - 1] 推导出来的,那么一定是从前到后遍历!

代码如下:

java 复制代码
for (int i = 2; i < nums.size(); i++) {
    dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
}
代码实现
java 复制代码
class Solution {
    public int rob(int[] nums) {
        int len = nums.length;
        if (len == 1) return nums[0];
​
        int[] dp = new int[len+1];
        dp[1] = nums[0];
​
        for (int i = 2; i <= len; i++) {
            dp[i] = Math.max(dp[i-1], dp[i-2]+nums[i-1]);
        }
​
        return dp[len];
    }
}
相关推荐
毕设源码-朱学姐42 分钟前
【开题答辩全过程】以 工厂能耗分析平台的设计与实现为例,包含答辩的问题和答案
java·vue.js
智者知已应修善业1 小时前
【求中位数】2024-1-23
c语言·c++·经验分享·笔记·算法
地平线开发者2 小时前
PTQ 量化数值范围与优化
算法·自动驾驶
sali-tec2 小时前
C# 基于halcon的视觉工作流-章68 深度学习-对象检测
开发语言·算法·计算机视觉·重构·c#
测试人社区-小明2 小时前
智能弹性伸缩算法在测试环境中的实践与验证
人工智能·测试工具·算法·机器学习·金融·机器人·量子计算
Spring AI学习2 小时前
Spring AI深度解析(9/50):可观测性与监控体系实战
java·人工智能·spring
罗西的思考3 小时前
【Agent】MemOS 源码笔记---(5)---记忆分类
人工智能·深度学习·算法
java1234_小锋3 小时前
Spring IoC的实现机制是什么?
java·后端·spring
xqqxqxxq4 小时前
背单词软件技术笔记(V2.0扩展版)
java·笔记·python
猫头虎4 小时前
又又又双叒叕一款AI IDE发布,国内第五款国产AI IDE Qoder来了
ide·人工智能·langchain·prompt·aigc·intellij-idea·ai编程