leetcode198打家劫舍

题目描述

LeetCode 第 198 题——打家劫舍(House Robber)

你是一个职业小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,这个地方所有的房屋都围成一圈,并且相邻的房屋有安全系统会相连,如果两间相邻的房屋在同一晚上被打劫,系统会自动报警。

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

示例 1:
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。

解题思路

这道题可以看作是一个斐波那契数列问题。因为要到达第 n 阶楼梯的方法数量等于到达第 n-1 阶楼梯和到达第 n-2 阶楼梯的方法数量之和。
具体来说:
到达第 n 阶楼梯的方法 = 到达第 n-1 阶楼梯的方法 + 到达第 n-2 阶楼梯的方法。
当 n=1 时,只有一种方法。
当 n=2 时,有两种方法。
因此,我们可以用动态规划来解决这个问题,使用一个数组或两个变量来存储到达每一阶楼梯的方法数量。

解题步骤

1.判断 n 是否小于或等于 2,如果是,直接返回 n。
2.初始化两个变量 a 和 b 分别代表到达 n-2 和 n-1 阶楼梯的方法数量,并设定初始值为 1 和 2。
3.从 3 开始遍历到 n,每一步更新 a 和 b 的值,b 的新值为 a 和 b 之和,而 a 的新值为原先 b 的值。
4.返回 b 的值,即为最终的答案。

具体步骤

1.如果房屋数量为 0,直接返回 0。
2.如果房屋数量为 1,直接返回该房屋的金额。
3.初始化一个长度为 n 的数组 dp,其中 dp[i] 表示到达第 i 间房屋时能够偷窃到的最高金额。
4.dp[0] 初始化为第一个房屋的金额,dp[1] 初始化为 max(nums[0], nums[1]),表示前两个房屋中金额较大者。
5.从第 2 间房屋开始,通过递推公式 dp[i] = max(dp[i-1], dp[i-2] + nums[i]) 计算出每间房屋能够偷窃到的最高金额。
6.返回 dp[n-1] 作为最终结果,即为到达最后一个房屋时能够偷窃到的最高金额。

代码实现

func rob(nums []int) int {
	n := len(nums)
   // 如果房屋数量为 0,直接返回 0
	if n == 0 {
		return 0
	}
   // 如果房屋数量为 1,直接返回该房屋的金额
	if n == 1 {
		return nums[0]
	}
	// 初始化动态规划数组 dp
	dp := make([]int, n)
	dp[0] = nums[0]
	dp[1] = max(nums[0], nums[1])
     // 初始化第一个房屋和前两个房屋的最大偷窃金额
	for i := 2; i < n; i++ {
		dp[i] = max(dp[i-1], dp[i-2]+nums[i])
	}
	// 返回最后一个房屋的最高偷窃金额
	return dp[n-1]
}

// max 函数返回两个整数中的最大值
func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

代码测试

func main() {
	// 测试用例
	testCases := [][]int{
		{1, 2, 3, 1},
		{2, 7, 9, 3, 1},
		{2, 1, 1, 2},
		{5, 3, 4, 11, 2},
	}

	// 遍历测试用例并输出结果
	for _, nums := range testCases {
		fmt.Printf("房屋金额: %v, 最高偷窃金额: %d\n", nums, rob(nums))
	}
}

测试结果

在这里插入图片描述

关于题目疑问

Q1 dp[i] = max(dp[i-1], dp[i-2] + nums[i]) 这个递推公式是怎么算出来的

我们要解决的问题是:在一排房屋中,小偷不能同时偷窃相邻的两间房屋,求能偷窃到的最大金额。
假设我们已经计算到了第 i 间房屋,面临两个选择:
不偷第 i 间房屋:那么小偷能获得的最大金额就是前一间房屋的最大偷窃金额,即 dp[i-1]。
偷第 i 间房屋:由于不能偷相邻的房屋,因此小偷只能选择从第 i-2 间房屋开始偷,这时的最大偷窃金额为 dp[i-2],再加上第 i 间房屋的金额 nums[i],总金额为 dp[i-2] + nums[i]。

递推公式推导:
基于上面的分析,我们可以得出:
如果小偷选择不偷第 i 间房屋,最大金额为 dp[i-1]。
如果小偷选择偷第 i 间房屋,最大金额为 dp[i-2] + nums[i]。
为了保证小偷获得的总金额最大,我们在这两种选择中取较大值
dp[i] = max(dp[i-1], dp[i-2] + nums[i])

总结

dp[i] 的值取决于是否选择偷窃当前的房屋 i,以及偷窃之前房屋的情况。
递推公式 dp[i] = max(dp[i-1], dp[i-2] + nums[i]) 就是基于这两种选择所能获得的最大金额计算出来的。
最终,dp[n-1] 就是小偷在 n 间房屋内所能获得的最大金额。

Q2 什么是动态规划?

动态规划(Dynamic Programming,简称 DP)是一种算法设计技巧,用于解决具有重叠子问题和最优子结构性质的问题。它的核心思想是通过将问题分解为更小的子问题,逐步求解并保存这些子问题的解,从而构建出原问题的解。动态规划通常用于优化问题,尤其是那些存在多种可能选择或路径的问题。

例子分析
举例来说,abb 和 egg 是同构的,因为可以通过如下映射来匹配:
a -> e
b -> g
这意味着字符串 s 中的每个字符都可以找到一个对应的字符 t,并且这个映射在整个字符串中是一致的。

动态规划核心思想

重叠子问题:
问题可以被分解为多个子问题,这些子问题之间存在重叠,也就是说,同一个子问题会被多次计算。
例如,在计算斐波那契数列时,F(n) = F(n-1) + F(n-2),其中 F(n-1) 和 F(n-2) 是重复计算的子问题。
最优子结构:
一个问题的最优解可以通过其子问题的最优解组合而成。
例如,在最短路径问题中,找到从起点到终点的最短路径可以通过找到从起点到某个中间节点的最短路径,再加上从该中间节点到终点的最短路径来实现。
状态转移方程:
动态规划通过状态转移方程来表示问题的递推关系。这个方程通常是基于问题的最优子结构性质来构建的。
例如,在打家劫舍问题中,状态转移方程是 dp[i] = max(dp[i-1], dp[i-2] + nums[i]),表示到第 i 间房屋时的最大偷窃金额。
存储中间结果:
为了避免重复计算,动态规划会存储已经计算过的子问题的结果,通常使用数组或表来保存这些中间结果。
例如,在计算斐波那契数列时,可以用一个数组来存储每一个 F(n) 的值,避免重复计算。

动态规划步骤

1.定义状态:确定如何表示问题的子问题,通常使用一个数组或表格来表示不同状态。例如,在打家劫舍问题中,dp[i] 表示从第 0 到第 i 间房屋的最大偷窃金额。
2.构建状态转移方程:根据问题的最优子结构,确定如何从一个状态转移到另一个状态。例如,在打家劫舍问题中,状态转移方程为 dp[i] = max(dp[i-1], dp[i-2] + nums[i])。
3.初始化:为状态数组或表格设定初始值。例如,斐波那契数列中,F(0) 和 F(1) 需要被初始化为 0 和 1。
4.计算并填表:根据状态转移方程,从初始状态开始逐步计算出所有的状态。
5.输出结果:最后输出表格中保存的最终结果。

总结

动态规划是一种非常强大的算法设计方法,适用于解决优化类问题,特别是那些具有重叠子问题和最优子结构的场景。它通过逐步解决子问题并存储结果来避免重复计算,从而显著提高了效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/870461.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL进阶之路】数据库的操作

目录 创建数据库 字符集和校验规则 查看数据库支持的字符集 查看数据库支持的字符集校验规则 指定字符集和校验规则 在配置文件中配置 查看数据库 显示创建语句 修改数据库 删除数据库 数据库的备份和恢复 备份整个数据库 备份特定表 备份多个数据库 备份所有数据…

linux,docker查看资源消耗总结

在linux和docker中我们将一个程序运行到后台&#xff0c;之后我们想查看它的运行状态&#xff0c;对于服务器的资源消耗等等 1.linux查看进程 ps aux | grep python ps aux&#xff1a;列出所有正在运行的进程。grep python&#xff1a;过滤出包含 python 的进程 2.linux查…

Mapreduce_Distinct数据去重

MapReduce中数据去重 输入如下的数据&#xff0c;统计其中的地址信息&#xff0c;并对输出的地址信息进行去重 实现方法&#xff1a;Map阶段输出的信息K2为想要去重的内容&#xff0c;利用Reduce阶段的聚合特点&#xff0c;对K2进行聚合&#xff0c;去重。在两阶段中&#xff…

Java之线程篇一

目录 如何理解进程&#xff1f; 进程和线程的区别 线程的优点 线程的缺点 线程异常 线程用途 创建线程 方法一&#xff1a;继承Thread类&#xff0c;重写run() 观察线程 小结 方法二&#xff1a; 实现Runnable接口&#xff0c;重写run() 方法三&#xff1a;继承Threa…

【深度学习】【语音TTS】GPT-SoVITS v2 实战,训练一个人的音色,Docker镜像

文章目录 原理Dockerdocker push训练教程: https://www.yuque.com/baicaigongchang1145haoyuangong/ib3g1e/xyyqrfwiu3e2bgyk 原理 Docker 不用docker不行,不好分配显卡, 做个docker镜像: docker pull pytorch/pytorch:2.1.2

C++练习备忘录

1. 保留两位小数输出格式 #include <iostream> #include <iomanip> using namespace std; int main() {double S 0;S (15 25) * 20 / 2;cout << fixed << setprecision(2) << S;return 0; }2. 设置输出宽度 #include <iostream> #inclu…

[论文笔记]ZeRO: Memory Optimizations Toward Training Trillion Parameter Models

引言 今天带来ZeRO: Memory Optimizations Toward Training Trillion Parameter Models的论文笔记。 大型深度模型提供了显著的准确性提升&#xff0c;但训练数十亿到数万亿个参数是具有挑战性的。现有的解决方案&#xff0c;如数据并行和模型并行&#xff0c;存在基本的局限…

查看一个exe\dll文件的依赖项

方法 使用一个Dependencies工具&#xff0c;检测exe文件的所有依赖项 工具使用 下载压缩包之后解压&#xff0c;解压后如下图所示 在命令行中运行Dependencies.exe程序会得到帮助菜单 查询某exe的所有依赖项&#xff0c;使用命令 Dependencies.exe -chain <查询文件> …

OpenSSL源码编译及Debug

** 1. 环境 Linux 5.19.0-14-generic 22.04.1-Ubuntu 2. 所需工具 gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04) cmake version 3.22.1 3. 步骤 3.1 获取openssl源码 方法可以git clone获得源码&#xff0c;或者直接去GitHub上下载压缩包&#xff0c;GitHub网址&#xf…

spring data:spring-data-jdbc spring-data-relational 源码解析 (2)

文章目录 简介项目特点解决的主要问题关联的项目如何引入到项目工程中源码分析框架 最近这几年在做数据中台相关的项目&#xff0c;有个技术点就是要支持多款数据库&#xff0c;尤其是一些国产数据库&#xff0c; sql 语法多样&#xff0c;如何做统一就是一个我们面临的一个难题…

[Python办公]Pandas创建透视表入门2

pivot_table 透视表在 Pandas 中是一个非常强大和灵活的工具&#xff0c;它支持许多高级功能&#xff0c;可以用于复杂的数据分析和报告生成。以下是一些更高级的用法和详细说明 1. 多级索引&#xff08;MultiIndex&#xff09; pivot_table 支持多级索引&#xff0c;这意味着…

稚晖君发布5款全能人形机器人,开源创新,全能应用

8月18日&#xff0c;智元机器人举行“智元远征 商用启航” 2024年度新品发布会&#xff0c;智元联合创始人彭志辉主持并发布了“远征”与“灵犀”两大系列共五款商用人形机器人新品——远征A2、远征A2-W、远征A2-Max、灵犀X1及灵犀X1-W&#xff0c;并展示了在机器人动力、感知、…

ArcGis在线地图插件Maponline(好用版)

ArcGis加载插件&#xff0c;可在线浏览谷歌地图、天地图、高德地图、必应地图等多种&#xff0c;包含街道、影像、标注地图等信息&#xff08;谷歌地图需自备上网手段&#xff09;&#xff0c;免费注册账号即可使用&#xff0c;可加载无水印底图。 与大地2000坐标无需配准直接使…

vue3旋转木马型轮播图,环型滚动

<template><div><div class"content"><div class"but1" click"rotateLeft">--向左</div><div class"ccc"><main id"main"><div class"haha" ref"haha"&g…

Mac 中安装内网穿透工具ngrok

ngrok 是什么&#xff1f; Ngrok 是一个网络工具&#xff0c;主要用于在网络中创建从公共互联网到私有或本地网络中运行的web服务的安全隧道。它充当了一个反向代理&#xff0c;允许外部用户通过公共可访问的URL访问位于防火墙或私有网络中的web应用程序或服务。Ngrok 特别适用…

Memcached深度解析:提升Web应用性能的内存缓存利器

一、引言 1. 介绍Web应用性能的重要性 在当今数字化时代&#xff0c;Web应用已成为企业与用户交互的主要渠道。用户对Web应用的期望越来越高&#xff0c;不仅要求功能丰富&#xff0c;还要求响应迅速、操作流畅。Web应用的性能直接影响到用户体验&#xff0c;进而关系到用户满…

Python Django功能强大的扩展库之channels使用详解

概要 随着实时 web 应用程序的兴起,传统的同步 web 框架已经无法满足高并发和实时通信的需求。Django Channels 是 Django 的一个扩展,旨在将 Django 从一个同步 HTTP 框架转变为一个支持 WebSockets、HTTP2 和其他协议的异步框架。它不仅能够处理传统的 HTTP 请求,还可以处…

mac清理软件哪个好用免费 MacBook电脑清理软件推荐 怎么清理mac

随着使用时间的增长&#xff0c;mac电脑会积累一些不必要的垃圾文件&#xff0c;这些文件会占用宝贵的存储空间&#xff0c;影响电脑的运行速度和稳定性。因此&#xff0c;定期清理mac电脑的垃圾文件是非常有必要的。市场上有许多优秀的Mac清理软件&#xff0c;包括一些出色的国…

MySQL零散拾遗(四)--- 使用聚合函数时需要注意的点点滴滴

聚合函数 聚合函数作用于一组数据&#xff0c;并对一组数据返回一个值。 常见的聚合函数&#xff1a;SUM()、MAX()、MIN()、AVG()、COUNT() 对COUNT()聚合函数的更深一层理解 COUNT函数的作用&#xff1a;计算指定字段在查询结果中出现的个数&#xff08;不包含NULL值&#…

《昇思25天学习打卡营第2天|张量》

张量其实就是矩阵&#xff0c;在python中主要是使用numpy这个库来操作&#xff0c;然后再mindspore中一般使用tensor对象作为张量的载体 张量如果维度只有二维的话可以简单理解为数据库中的表&#xff0c;但是如果是3维4维主要是在列表中增加列表项比如 【 【1&#xff0c;1】…