每日一题——打家劫舍

news/2025/2/22 6:15:32

打家劫舍(一)与打家劫舍(二)动态规划解法详解

    • 打家劫舍(一)
      • 问题描述
      • 示例
      • 解题思路
        • 动态规划
      • 代码实现
      • 复杂度分析
    • 打家劫舍(二)
      • 问题描述
      • 示例
      • 解题思路
        • 环形问题的拆分
      • 代码实现
      • 复杂度分析
    • 总结

打家劫舍(一)

问题描述

你是一个经验丰富的小偷,准备偷沿街的一排房间,每个房间都存有一定的现金。不能偷相邻的两家。给定一个整数数组 nums,数组中的元素表示每个房间存有的现金数额,计算在不被发现的前提下最多的偷窃金额。

数据范围
数组长度满足 (1 \leq n \leq 2 \times 10^5),数组中每个值满足 (1 \leq \text{nums}[i] \leq 5000)。


示例

输入输出说明
[1, 2, 3, 4]6偷第 2、4 个房间
[1, 3, 6]7偷第 1、3 个房间
[2, 10, 5]10偷第 2 个房间

解题思路

动态规划
  1. 状态定义

    • dp[i] 表示考虑前 i 个房间时的最大偷窃金额。
  2. 状态转移方程

    • 当前房间有两种选择:
      • 不偷:继承前一个房间的最大金额(dp[i-1])。
      • :当前房间金额 + 前前一个房间的最大金额(dp[i-2] + nums[i])。
    • 因此:
      [
      dp[i] = \max(dp[i-1], \ dp[i-2] + \text{nums}[i])
      ]
  3. 边界条件

    • dp[0] = nums[0]:只有一个房间时只能偷它。
    • dp[1] = \max(nums[0], nums[1]):两个房间时偷金额较大的。

代码实现

int rob(int* nums, int numsLen) {
    // 如果数组长度小于等于0,说明没有房子可以偷,直接返回0
    if (numsLen <= 0) return 0;

    // 如果数组长度为1,说明只有一间房子,直接返回这间房子的金额
    if (numsLen == 1) return nums[0];

    // 如果数组长度为2,说明有两间房子,选择金额较大的那间房子
    if (numsLen == 2) return (nums[0] > nums[1]) ? nums[0] : nums[1];

    // 定义一个动态规划数组dp,dp[i]表示到第i间房子为止,小偷能偷到的最大金额
    int dp[numsLen];

    // 初始化dp数组的前两个值
    // 如果只有一间房子,最大金额就是这间房子的金额
    dp[0] = nums[0];
    // 如果有两间房子,最大金额是这两间房子中金额较大的那个
    dp[1] = (nums[0] > nums[1]) ? nums[0] : nums[1];

    // 遍历数组,从第三间房子开始计算
    for (int i = 2; i < numsLen; i++) {
        // 对于第i间房子,有两种选择:
        // 1. 不偷第i间房子,最大金额就是dp[i-1](即前一间房子的最大金额)
        // 2. 偷第i间房子,最大金额是dp[i-2] + nums[i](即前两间房子的最大金额加上当前房子的金额)
        // dp[i]的值是这两种选择中的较大值
        dp[i] = (dp[i - 1] > (dp[i - 2] + nums[i])) ? dp[i - 1] : (dp[i - 2] + nums[i]);
    }

    // 返回dp数组的最后一个值,即所有房子的最大金额
    return dp[numsLen - 1];
}

复杂度分析

  • 时间复杂度:(O(n)),遍历一次数组。
  • 空间复杂度:(O(n)),存储动态规划数组。

打家劫舍(二)

问题描述

沿湖的房间组成一个闭合的圆形,即第一个房间和最后一个房间视为相邻。给定一个长度为 n 的整数数组 nums,计算在不被发现的前提下最多的偷窃金额。

数据范围:与打家劫舍(一)相同。


示例

输入输出说明
[1, 2, 3, 4]6偷第 2、4 个房间
[1, 3, 6]6偷第 3 个房间

解题思路

环形问题的拆分

由于首尾房间相邻,问题可拆分为两种情况:

  1. 不偷第一个房间:计算区间 [1, n-1] 的最大偷窃金额。
  2. 不偷最后一个房间:计算区间 [0, n-2] 的最大偷窃金额。

最终结果为两种情况的最大值。


代码实现

// 辅助函数:计算从 start 到 end 的最大偷窃金额
int robRange(int* nums, int start, int end) {
    int n = end - start + 1; // 计算从 start 到 end 的区间长度
    if (n == 1) return nums[start]; // 如果区间内只有一间房子,直接返回这间房子的金额

    // 定义动态规划数组 dp,dp[i] 表示从 start 开始到第 i 间房子的最大偷窃金额
    int dp[n];
    dp[0] = nums[start]; // 初始化第一间房子的最大金额
    dp[1] = (nums[start] > nums[start + 1]) ? nums[start] : nums[start + 1]; // 初始化前两间房子的最大金额

    // 遍历从第 3 间房子到最后一间房子
    for (int i = 2; i < n; i++) {
        int current = start + i; // 当前房子在原数组中的索引
        // 状态转移方程:选择当前房子或不选择当前房子的最大金额
        dp[i] = (dp[i - 1] > (dp[i - 2] + nums[current])) ? dp[i - 1] : (dp[i - 2] + nums[current]);
    }

    // 返回从 start 到 end 的最大偷窃金额
    return dp[n - 1];
}
int rob(int* nums, int numsLen) {
    // 如果只有一间房子,直接返回这间房子的金额
    if (numsLen == 1) return nums[0];
    // 如果有两间房子,返回两间房子中金额较大的那个
    if (numsLen == 2) return (nums[0] > nums[1]) ? nums[0] : nums[1];

    // 分两种情况讨论:
    // 1. 不偷最后一间房子,计算从第 0 间到第 (numsLen - 2) 间房子的最大金额
    int case1 = robRange(nums, 0, numsLen - 2);
    // 2. 不偷第一间房子,计算从第 1 间到第 (numsLen - 1) 间房子的最大金额
    int case2 = robRange(nums, 1, numsLen - 1);

    // 返回两种情况中的较大值
    return (case1 > case2) ? case1 : case2;
}

复杂度分析

  • 时间复杂度:(O(n)),两次遍历数组。
  • 空间复杂度:(O(n)),存储动态规划数组。

总结

问题动态规划状态转移方程关键点
打家劫舍(一)dp[i] = max(dp[i-1], dp[i-2] + nums[i])线性数组,直接遍历
打家劫舍(二)拆分两种情况求最大值环形数组,避免首尾同时偷窃

http://www.niftyadmin.cn/n/5861760.html

相关文章

豆包 Marscode + deepseek-R1 使用体验

拥抱 deepseek 这次豆包 Marscode 的新特性&#xff0c;是可以选择当下最热门的 deepseek 的两款模型&#xff1a;V3 和 R1&#xff0c;这让原本好用的 ai 插件&#xff0c;更加好用了&#xff0c;而且是免费使用&#xff0c;程序员的生产力再一次得到提升。 使用过程中的几…

OSPF基础知识总结

基本概念 协议类型:链路状态型IGP(内部网关协议),基于Dijkstra算法计算最短路径树。 协议号:IP层协议,协议号89。 特点:支持分层设计(区域划分)、快速收敛、无环路、支持VLSM/CIDR。 区域(Area) 骨干区域(Backbone Area):Area 0,所有非骨干区域必须直接或通过虚…

信创浪潮下,以 OpManager筑牢安全运维防线

在数字化转型加速和国际形势复杂多变的当下&#xff0c;信创产业的重要性愈发凸显。信创&#xff0c;即信息技术应用创新&#xff0c;旨在实现信息技术领域的自主可控&#xff0c;涵盖从芯片、操作系统、数据库到应用软件等一系列关键技术和产品。它不仅是推动产业升级的重要力…

Spring Cloud — Hystrix 服务隔离、请求缓存及合并

Hystrix 的核心是提供服务容错保护&#xff0c;防止任何单一依赖耗尽整个容器的全部用户线程。使用舱壁隔离模式&#xff0c;对资源或失败单元进行隔离&#xff0c;避免一个服务的失效导致整个系统垮掉&#xff08;雪崩效应&#xff09;。 1 Hystrix监控 Hystrix 提供了对服务…

Nginx Embedded Variables 嵌入式变量解析(4)

Nginx Embedded Variables 嵌入式变量解析(4) 相关链接 nginx 嵌入式变量解析目录nginx 嵌入式变量全目录nginx 指令模块目录nginx 指令全目录 一、目录 1.1 变量目录 1.1.24 ngx_stream_core_module $binary_remote_addr $bytes_received $bytes_sent $connection $hos…

数据结构系列二:包装类+泛型

包装类泛型 一、包装类&#xff08;1&#xff09;基本数据类型和对应的包装类&#xff08;2&#xff09;装箱和拆箱 二、泛型&#xff08;1&#xff09;什么是泛型&#xff08;2&#xff09;引出泛型&#xff08;3&#xff09;语法&#xff08;4&#xff09;泛型类的使用1.语法…

SpringCloud-OpenFeign初步使用

在使用RestTemplate时,会发现拼接URL时非常不美观,并且在参数多了以后拼接起来也容易出错,而Feign就是为了解决这个问题,让远程调用像调用本地方法一样优雅且方便. 功能: 更优雅的进行远程调用 使用方法: 引入依赖,由于OpenFeign是基于负载均衡的所以要引入三个依赖,openFei…

【信息系统项目管理师-案例真题】2022下半年案例分析答案和详解

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 试题一(24分)【问题1】(6分)【问题2】(10分)【问题3】(8分)试题二(26分)【问题1】(8分)【问题2】(8分)【问题3】(4分)【问题4】(6分)试题三(25分)【问题1】(12分)【问题2】(7分)【问题…