【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 <= numsi <= 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)以及下标的含义

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

  1. 定递推公式

决定dpi的因素就是第i房间偷还是不偷。

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

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

然后dpi取最大值,即dpi = max(dpi - 2 + numsi, dpi - 1);

  1. dp数组如何初始化

从递推公式dpi = max(dpi - 2 + numsi, dpi - 1);可以看出,递推公式的基础就是dp0 和 dp1

从dpi的定义上来讲,dp0 一定是0,dp1就是nums0

代码如下:

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

dpi 是根据dpi - 2 和 dpi - 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];
    }
}
相关推荐
To_OC8 小时前
LC 51 N 皇后:我以为难的是回溯,结果栽在了对角线下标
javascript·算法·leetcode
腻害兔8 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
2401_841495649 小时前
【操作系统】进程同步与互斥实验报告
c++·算法·操作系统·进程·并发·同步·互斥
码智社9 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
萧瑟余晖10 小时前
JDK 26 新特性详解
java·开发语言
马优晨10 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
爱刷碗的苏泓舒13 小时前
PPP-AR 中的参考星选取:数学原理、评价指标与切换处理
算法·gnss·模糊度固定·ppp-ar·星间单差·参考星·卫星端偏差
维天说13 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
Zane199414 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端