数据结构与算法——从递归入手一维动态规划【1】

前言:

简单记录对左程云系列算法课程--算法讲解066【必备】的学习,这是第一篇。主要提供C++代码和一些简单的个人理解,如需要细致讲解请移步原视频。

涉及内容:

斐波那契数列、动态规划

参考视频:

左程云--算法讲解066【必备】从递归入手一维动态规划

题目列表:

1.Leetcode--509. 斐波那契数
2.Leetcode--983. 最低票价
3.Leetcode--91. 解码方法
4.Leetcode--639. 解码方法 II

题目解答:

⭐1.Leetcode--509. 斐波那契数
题目:

解题思考:

如果使用简单的递归,则会发现会有很多重复的递归的计算,所以为了优化,可以使用数组存放每一个 f (n) 对应的值,这样就可以避免重复计算,这就是记忆化搜索。而递归一般可以使用迭代完成,即从顶向下到从底向上,再由于我们计算 f (n) 时我们只需要 f (n - 1)f (n - 2) ,所以我们只需要两个变量。

小结:看似是斐波那契数列,其实是整个一维动态规划的思考过程,学会思路比做题更重要。

递归 -> 记忆化搜索 -> 迭代 -> 空间优化

三个阶段(省去迭代版本)代码如下。

示例代码:
①纯递归
class Solution {
public:int fib(int n) {return func(n);}int func(int n) {if(n == 0) {return 0;}if(n == 1) {return 1;}return func(n - 1) + func(n - 2);}
};
②记忆化
class Solution {
private:vector<int> dp;
public:int fib(int n) {dp.resize(n + 1, -1);return func(n);}int func(int n) {if(n == 0) {return 0;}if(n == 1) {return 1;}if(dp[n] != -1) {return dp[n];}dp[n] = func(n - 1) + func(n - 2);return dp[n]; }
};
③最终优化
class Solution {
public:int fib(int n) {int f0 = 0;int f1 = 1;if (n == 0) { return 0; }if (n == 1) { return 1; }for(int i = 0; i < n - 1; i++){int f = f1 + f0;f0 = f1;f1 = f;}return f1;}
};
⭐2.Leetcode--983.最低票价
题目:

解题思考:

起初自己写时想到了从左向右迭代求解,但是始终没有码出来,直到后来参考别人代码才完成从左向右的迭代。状态方程思路是对的,错误在于没有把非旅游日期的对应最小花费更新,总想着去判断其是否为旅游日期。示例代码如下。

而左老师的代码是从后向左迭代求解的,我个人认为是不如从左向右更加容易理解。示例代码也如下。都已通过测试。

示例代码:
①从左向右
class Solution {
private:int lastDay;int dp[366] = {0};
public:int mincostTickets(vector<int>& days, vector<int>& costs) {lastDay = days[days.size() - 1];int index = 0;for(int i = 1; i <= lastDay; i++){if(i == days[index]){int f1 = dp[i - 1] + costs[0];int f2 = (i >= 7 ? dp[i - 7] : 0) + costs[1];int f3 = (i >= 30 ? dp[i - 30] : 0) + costs[2];dp[i] = min(f1, f2);dp[i] = min(dp[i], f3);index++;}else{dp[i] = dp[i - 1];}}return dp[lastDay];}
};
②从右向左
class Solution {
private:int durations[3] = { 1, 7, 30 };
public:int mincostTickets(vector<int>& days, vector<int>& costs) {int n = days.size();vector<int> dp(n + 1, INT_MAX);dp[n] = 0;for(int i = n - 1; i >= 0; i--){for(int k = 0, j = i + 1; k <= 2; k++){while(j < n && days[i] + durations[k] > days[j]){j++;}dp[i] = min(dp[i], costs[k] + dp[j]);}}return dp[0];}
};
⭐3.Leetcode--91. 解码方法
题目:

解题思考:

本题其实没有特别的点,注意一下编码'0'的判断即可,按递归->记忆化->动态规划写就行了。

示例代码:
①纯递归(超时)
class Solution {
private:string _s;
public:int numDecodings(string s) {_s = s;return getCount(0);}int getCount(int i) {if(i == _s.size()){return 1;}int ans;if(_s[i] == '0') {ans = 0;}else{ans = getCount(i + 1);if(i + 1 < _s.size() && (_s[i] - '0') * 10 + (_s[i + 1] - '0') <= 26){ans += getCount(i + 2);}}return ans;}};
②记忆化(通过)
class Solution {
private:string _s;vector<int> dp;
public:int numDecodings(string s) {_s = s;int len = s.size();dp.resize(len, -1);return getCount(0);}int getCount(int i) {if(i == _s.size()){return 1;}if(dp[i] != -1){return dp[i];}int ans;if(_s[i] == '0') {ans = 0;}else{ans = getCount(i + 1);if(i + 1 < _s.size() && (_s[i] - '0') * 10 + (_s[i + 1] - '0') <= 26){ans += getCount(i + 2);}}dp[i] = ans;return ans;}};
③动态规划
class Solution {
public:int numDecodings(string s) {int n = s.size();vector<int> dp(n + 1, -1);dp[n] = 1;for(int i = n - 1; i >= 0; i--){if(s[i] == '0'){dp[i] = 0;}else{dp[i] = dp[i + 1];if(i + 1 < n && (s[i] - '0') * 10 + (s[i + 1] - '0') <= 26){dp[i] += dp[i + 2];}}}return dp[0];}
};
④空间优化
class Solution {
public:int numDecodings(string s) {int n = s.size();int next = 1;int nextnext = 0;int cur;for(int i = n - 1; i >= 0; i--){if(s[i] == '0'){cur = 0;}else{cur = next;if(i + 1 < n && (s[i] - '0') * 10 + (s[i + 1] - '0') <= 26){cur += nextnext;}}nextnext = next;next = cur;}return next;}
};
⭐4.Leetcode--639. 解码方法 II
题目:

解题思考:

本题与上一题类似,无非是讨论的情况比较多,这里推荐观看原视频,左老师讲的非常清晰,我在这里仅提供对应代码。

示例代码:
①纯递归(超时)
class Solution {
private:string _s;int len;long mod = 1e9 + 7;
public:int numDecodings(string s) {_s = s;len = s.size();return (int)getCount(0);}int getCount(int i){if(i == len){return 1;}if(_s[i] == '0'){return 0;}unsigned long long ans = 0;if(_s[i] == '*'){ans = (unsigned long long)9 * getCount(i + 1);}else{ans = getCount(i + 1);}if(i + 1 < len){// num, num// num, *// * , num// * , *if(_s[i] != '*'){//num, num//num, *if(_s[i + 1] != '*'){//num, numif((_s[i] - '0') * 10 + (_s[i + 1] - '0') <= 26){ans += getCount(i + 2);}}else{//num, *if(_s[i] == '1'){ans += (unsigned long long)9 * getCount(i + 2);}if(_s[i] == '2'){ans += (unsigned long long)6 * getCount(i + 2);}}}else{//*, num//*, *if(_s[i + 1] != '*'){//*, numif(_s[i + 1] <= '6'){ans += (unsigned long long)2 * getCount(i + 2);}else{ans += getCount(i + 2);}}else{//*, *ans += (unsigned long long)15 * getCount(i + 2);}}}ans = ans % mod;return ans;}
};
②记忆化
class Solution {
private:string _s;int n;long mod = 1e9 + 7;vector<unsigned long long> dp;
public:int numDecodings(string s) {_s = s;n = s.size();dp.resize(n, -1);return (int)getCount(0);}int getCount(int i){if(i == n){return 1;}if(_s[i] == '0'){return 0;}if(dp[i] != -1){return dp[i];}unsigned long long ans = 0;if(_s[i] == '*'){ans = (unsigned long long)9 * getCount(i + 1);}else{ans = getCount(i + 1);}if(i + 1 < n){// num, num// num, *// * , num// * , *if(_s[i] != '*'){//num, num//num, *if(_s[i + 1] != '*'){//num, numif((_s[i] - '0') * 10 + (_s[i + 1] - '0') <= 26){ans += getCount(i + 2);}}else{//num, *if(_s[i] == '1'){ans += (unsigned long long)9 * getCount(i + 2);}if(_s[i] == '2'){ans += (unsigned long long)6 * getCount(i + 2);}}}else{//*, num//*, *if(_s[i + 1] != '*'){//*, numif(_s[i + 1] <= '6'){ans += (unsigned long long)2 * getCount(i + 2);}else{ans += getCount(i + 2);}}else{//*, *ans += (unsigned long long)15 * getCount(i + 2);}}}ans = ans % mod;dp[i] = ans;return ans;}
};
③动态规划
class Solution {
private:string _s;int n;long mod = 1e9 + 7;vector<unsigned long long> dp;public:int numDecodings(string s) {_s = s;n = s.size();dp.resize(n + 1, -1);dp[n] = 1;for (int i = n - 1; i >= 0; i--) {if(_s[i] == '0'){dp[i] = 0;continue;}if (_s[i] == '*') {// ans = (unsigned long long)9 * getCount(i + 1);dp[i] = (unsigned long long)9 * dp[i + 1];} else {// ans = getCount(i + 1);dp[i] = dp[i + 1];}if (i + 1 < n) {// num, num// num, *// * , num// * , *if (_s[i] != '*') {// num, num// num, *if (_s[i + 1] != '*') {// num, numif ((_s[i] - '0') * 10 + (_s[i + 1] - '0') <= 26) {// ans += getCount(i + 2);dp[i] += dp[i + 2];}} else {// num, *if (_s[i] == '1') {// ans += (unsigned long long)9 * getCount(i + 2);dp[i] += (unsigned long long)9 * dp[i + 2];}if (_s[i] == '2') {// ans += (unsigned long long)6 * getCount(i + 2);dp[i] += (unsigned long long)6 * dp[i + 2];}}} else {//*, num//*, *if (_s[i + 1] != '*') {//*, numif (_s[i + 1] <= '6') {// ans += (unsigned long long)2 * getCount(i + 2);dp[i] += (unsigned long long)2 * dp[i + 2];} else {// ans += getCount(i + 2);dp[i] += dp[i + 2];}} else {//*, *// ans += (unsigned long long)15 * getCount(i + 2);dp[i] += (unsigned long long)15 * dp[i + 2];}}}dp[i] = dp[i] % mod;}return (int)dp[0];}
};
④空间压缩
class Solution {
private:string _s;int n;long mod = 1e9 + 7;// vector<unsigned long long> dp;
public:int numDecodings(string s) {_s = s;n = s.size();// dp.resize(n + 1, -1);// dp[n] = 1;unsigned long long next = 1;unsigned long long nextnext = 0;unsigned long long cur;for (int i = n - 1; i >= 0; i--) {if (_s[i] != '0') {if (_s[i] == '*') {// dp[i] = (unsigned long long)9 * dp[i + 1];cur = (unsigned long long)9 * next;} else {// dp[i] = dp[i + 1];cur = next;}if (i + 1 < n) {if (_s[i] != '*') {if (_s[i + 1] != '*') {if ((_s[i] - '0') * 10 + (_s[i + 1] - '0') <= 26) {// dp[i] += dp[i + 2];cur += nextnext;}} else {if (_s[i] == '1') {// dp[i] += (unsigned long long)9 * dp[i + 2];cur += (unsigned long long)9 * nextnext;}if (_s[i] == '2') {// dp[i] += (unsigned long long)6 * dp[i + 2];cur += (unsigned long long)6 * nextnext;}}} else {if (_s[i + 1] != '*') {if (_s[i + 1] <= '6') {// dp[i] += (unsigned long long)2 * dp[i + 2];cur += (unsigned long long)2 * nextnext;} else {// dp[i] += dp[i + 2];cur += nextnext;}} else {// dp[i] += (unsigned long long)15 * dp[i + 2];cur += (unsigned long long)15 * nextnext;}}}cur = cur % mod;}nextnext = next;next = cur;cur = 0;}return (int)next;}
};

最后:

这几道题基本就是套的左老师提供的思路模板,在此之前写动态规划只是思考动态方程以及如何递归和边界处理,这很显然会有很大的修改成本,而递归的修改成本就很小。当然,如果题目简单,则可以直接写,如遇到像第四题这种比较复杂的,优先写递归,之后按模板步骤来。第66节剩下的习题将在第二篇给出。

纯递归 -> 记忆化搜索 -> 动态规划 -> 空间压缩

最后,本文主要用于个人记录,如有错误还望指出,感谢你的阅读^_^。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

搭建个人博客系列--Nacos 注册中心

基础项目已完成&#xff0c;接下来就是SpringCloud的各种组件了。 那你又要问&#xff1a;既然有Nacos为什么之前还装了Apollo&#xff1f; 那你别管&#xff0c;那不得什么都会点&#xff0c;不然怎么找工作。干就完了。 一、安装Nacos 管他三七二十一&#xff0c;先在doc…

前端实习总结——案例与大纲

以下是一个结合真实场景的前端面试案例&#xff0c;包含面试流程、核心问题、候选人回答思路及面试官考察点&#xff0c;可直观感受如何在面试中展现实习/项目经历&#xff1a; 案例背景 候选人&#xff1a;应届生&#xff0c;有6个月前端实习经历&#xff0c;参与过“企业内部…

Web前端开发: :where(伪类函数选择器)

:where(伪类函数选择器)&#xff1a;:where() 是 CSS Selectors Level 4 规范中引入的一个强大的伪类函数选择器&#xff0c;它允许开发者以简洁的方式编写复杂的选择器&#xff0c;同时具有独特的优先级特性。核心概念&#xff1a;:where() 伪类函数选择器与 :is() 非常相似&a…

EfficientVMamba: Atrous Selective Scan for Light Weight Visual Mamba论文精读(逐段解析)

EfficientVMamba: Atrous Selective Scan for Light Weight Visual Mamba论文精读&#xff08;逐段解析&#xff09; 论文地址&#xff1a;https://arxiv.org/abs/2403.09977 CVPR 2024 Abstract. Prior efforts in light-weight model development mainly centered on CNN an…

Integer缓冲区

文章目录常见面试题&#xff1a;总结Integer缓冲区是Java预先创建的一个固定范围的Integer对象缓存池&#xff08;默认-128到127&#xff09;&#xff0c;用于自动复用频繁使用的整数值&#xff0c;减少内存开销和对象创建。当通过自动装箱或Integer.valueOf()生成该范围内的整…

[国家电网备考]计算机网络

计算机网络的概述 概念: 用通信设备与线路将地理位置不同,功能独立的计算机系统互连起来,以功能完善的网络软件实现网络中资源共享和信息传递的系统 自治计算机: 能够自我管理,配置,维护的计算机(目前我们使用的电脑) 以前的终端只有显示器,不能叫做自治计算机 计算机网络向用户…

在 Linux(openEuler 24.03 LTS-SP1)上安装 Kubernetes + KubeSphere 的防火墙放行全攻略

目录 在 Linux&#xff08;openEuler 24.03 LTS-SP1&#xff09;上安装 Kubernetes KubeSphere 的防火墙放行全攻略 一、为什么要先搞定防火墙&#xff1f; 二、目标环境 三、需放行的端口和协议列表 四、核心工具说明 1. 修正后的 exec.sh 脚本&#xff08;支持管道/重…

HTTP 响应头信息详解

HTTP 响应头信息详解 引言 HTTP(超文本传输协议)是互联网上应用最为广泛的网络协议之一。在HTTP协议中,响应头信息是服务器向客户端发送的重要信息之一。响应头信息包含了关于响应的元数据,如状态码、内容类型、缓存策略等。本文将详细介绍HTTP响应头信息的概念、类型、作…

去掉长按遥控器power键后提示关机、飞行模式的弹窗

首先找到对应长短按power键的位置&#xff1a;frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindowManager.javaprivate final Runnable mPowerLongPress new Runnable() {Overridepublic void run() {// The context isnt readif (mLongPressOnPowerBe…

Redis-哨兵机制Sentinel

redis的主从复制模式下,一旦主节点出现了故障无法提供服务了,需要人工进行主从切换,同时大量的客户端需要被通知切换到新的主节点上,对于有了一定规模的应用来说,这种方案的延迟是无法接受的,于是redis2.8提供了Redis-Sentinel(哨兵)来解决这个问题. 目录 1.啥是哨兵节点: 2.r…

SQL 视图

SQL 视图 引言 SQL 视图是数据库管理系统中的一种重要概念,它允许用户以不同的方式查看数据库中的数据。本文将详细介绍 SQL 视图的概念、作用、创建方法以及在实际应用中的注意事项。 一、SQL 视图的概念 SQL 视图是数据库中的一种虚拟表,它并不存储实际的数据,而是基于…

ESP32-使用VSCODE 各种问题总结汇总

1 问题 1 1.1 具体问题描述-config:idf.customExtraPath 无法正确描述launch.json 中使用了一个变量&#xff1a; ${config:idf.customExtraPaths}但在 VSCode 的设置中&#xff0c;并没有找到对应的设置项 idf.customExtraPaths&#xff0c;所以无法解析。 1.2 问题解决 1.2.1…

【剪裁Patch】已标注的WSI剪裁Patch的处理流程(以QuPath软件得到的标注信息为例)

1. 整体处理思路 整体处理流程如图所示,概括来说就是:根据标注信息将WSI区分为肿瘤区域和正常区域,对这个区域进行采样裁剪得到具有Patch级别标签的Patch。 当然,这里的Patch标签是根据标注信息决定的,如果标注的是癌症亚型信息,那么也可以将不同亚型的Patch区分出来。 …

Qt 与Halcon联合开发九:算法类设计与实现讲解(附源码)

一、设计背景 在机器视觉系统中&#xff0c;算法是系统的核心。不同产品、不同项目对图像处理的要求不尽相同&#xff0c;因此算法需要具备&#xff1a; 灵活拓展&#xff1a;方便添加新算法统一调用&#xff1a;界面或上层逻辑不关心算法细节结构清晰&#xff1a;便于维护与…

npu-driver 23.0.3驱动安装

宿主机器上安装npu-driver/ npu-firmware这两个东西 wget -O Ascend-hdk-910b-npu-driver_23.0.3_linux-aarch64.run https://bj.bcebos.com/v1/aipe-easyedge-public/cann/eb_speed/Ascend-hdk-910b-npu-driver_23.0.3_linux-aarch64.run?authorizationbce-auth-v1%2F50c8bb…

LeetCode题解---<三数之和>

文章目录题目<三数之和>--Python解法题解题目<三数之和>–Python解法 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为…

探索Insplorion氢气传感器:高灵敏度与快速响应的创新解决方案

在追求更清洁、更安全能源的过程中&#xff0c;氢气作为一种理想的清洁能源载体&#xff0c;正日益受到全球的重视。然而&#xff0c;氢气的广泛应用也带来了新的挑战——如何确保其储存、运输和使用的安全性&#xff1f;Insplorion通过其独特的纳米等离子体传感&#xff08;NP…

【QT】事件(鼠标、按键、定时器、窗口)

文章目录1. 事件1.1 事件的介绍1.2 事件的处理2. 按键事件3. 鼠标事件4. 定时器5. 窗口事件1. 事件 1.1 事件的介绍 事件是应用程序内部或者外部产生的事情或者动作的统称。 在 Qt 中使用⼀个对象来表示⼀个事件。所有的 Qt 事件均继承于抽象类 QEvent。事件是由系统或者 Qt …

STM32固件升级设计——串口IAP升级(基于YMODEM协议)

目录 一、功能描述 1、BootLoader部分&#xff1a; 2、APP部分&#xff1a; 二、BootLoader程序制作 1、分区定义 2、 主函数 3、YMODEM协议的实现 4、程序跳转 三、APP程序制作 四、工程配置&#xff08;默认KEIL5&#xff09; 五、运行测试 结束语 概述 IAP&…

Cookie(搭配domain)/Session(搭配HttpServletRequest+HttpSession)

各位看官&#xff0c;大家早安午安晚安呀~~~如果您觉得这篇文章对您有帮助的话欢迎您一键三连&#xff0c;小编尽全力做到更好 欢迎您分享给更多人哦今天我们来学习&#xff1a;Cookie/Session1.Cookie/Session的简述我们在讲解HTTP协议的时候已经讲解过Cookie了HTTP 协议自身是…