【Hello Algorithm】暴力递归到动态规划(二)

暴力递归到动态规划(二)

    • 背包问题
      • 递归版本
      • 动态规划
    • 数字字符串改字母字符串
      • 递归版本
      • 动态规划
    • 字符串贴纸
      • 递归版本
      • 动态规划

**特别需要注意的是 我们使用数组之前一定要进行初始化 不然很有可能会遇到一些意想不到的错误 比如说在Linux平台上 new出来的int数组会初始化为0 但是在leetcode网页上默认初始化确不是0 博主因为这个错误找了好久 **

由于缓存法(记忆化搜索)实在是太简单了 所以说从本篇博客开始 我们直接从递归到完整的动态规划 不再经历缓存法

背包问题

递归版本

现在给我们两个数组 一个数组表示货物的重量 一个数组表示货物的价值 它们的下标一一对应切一定大于等于0

现在给定我们一个参数bag 表示我们背包能够承受重量的最大值 现在要求背包能够装的价值的最大值

我们的思考过程如下

我们设置函数的意义是 从第index件货物开始拿 我们能拿进背包的最大价值

首先想base case

  • 如果此时背包的大小小于0 则说明背包无法装下任何货物 (背包大小可以为0 因为有可能货物的重量为0)
  • 如果index等于数组的长度 则说明没有任何货物了 返回0

之后我们写出的代码如下

int process(vector<int>& w , vector<int>& v , int index , int bag)      
{                                                                       if (bag < 0 )                                                         {                                                                     return 0;                                                           }                                                                     if (index == static_cast<int>(w.size()))                              {                                                                     return 0;                                                           }                                                                     int p1 = process(w , v , index + 1 , bag);                            int p2 = v[index] + process(w , v , index + 1 , bag - w[index]);      return  max(p1 , p2);                                                                                                         
}          

但是这里我们的base case其实是有问题的

因为如果我们只有一个货物 即使p2超重了 我们仍然会走p2这条分支 并且会拿走这个超重的货物 这显然是不合适的 所以说我们需要改写下base case和选择代码

修改后的代码如下

int process(vector<int>& w , vector<int>& v , int index , int bag)    
{                 if (bag < 0 )    {    return -1;                                }    if (index == static_cast<int>(w.size()))    {    return 0;                                   }              int p1 = process(w , v , index + 1 , bag);    int p2 = 0;        int next = process(w , v ,index + 1 , bag - w[index]);    if (next != -1)    {    p2 = v[index] + next;    }                                                                                                                             return  max(p1 , p2);    
} 

动态规划

我们观察下原函数

process(vector<int>& w , vector<int>& v , int index , int bag)    

变化的参数只有index 和 bag 所以说我们只要建立index和bag的二维表就能解决问题

我们首先看每个格子依赖于什么

  int p1 = process(w , v , index + 1 , bag);    int p2 = 0;        int next = process(w , v ,index + 1 , bag - w[index]);  

观察上面的两个函数 我们就能得到下图

在这里插入图片描述

每个格子依赖于它下面的两个格子 (如果存在的话)

所以说我们的动态规划要从最下面开始 从左往右填

  for (int dpindex = w.size() - 1 ; dpindex >= 0  ; dpindex--){for(int dpbag = 0; dpbag <= bag ; dpbag++){int p1 = dp[dpindex + 1][dpbag];int p2 = 0;if (dpbag - w[dpindex] >= 0){p2 = v[dpindex] + dp[dpindex+1][bag - w[dpindex]];}dp[dpindex][dpbag] = max(p1 , p2);}                                                                                                                           }

这样子我们的动态规划代码就完成了

数字字符串改字母字符串

递归版本

我们规定 1数字代表 ‘a’ 2数字代表 ‘b’ … … 以此类推

现在给你一串数字字符 要求你返回能改成字母字符串的最大解法

函数表示如下

int process(string& str , int index)

该函数的意义是 从str的index位置开始 按题目要求有的最大解法

我们首先来想base case

  • 如果index此时走到了str.size() 此时就是一个空串 空串也是一种解法 再拼接上前面的字符串 就是一种完整的解法
  • 如果index单独走到了数字0的位置 那么此时就没有解法了

之后我们来想普遍情况 当前字符单独转化 ? 还是当前字符 + 下面一个字符转化 ?

当然如果是当前字符 + 下面一个字符转化的话我们要考虑一些特殊情况

代码表示如下

int process(string& str , int index)
{            if (index == static_cast<int> (str.length())){return 1;           }if (str[index] == '0'){return 0; }                 // need cur // need cur + 1 ?                                                                                        int p1 = process(str , index + 1);                                                                                            int p2 = 0;                     if (index + 1 < static_cast<int>(str.length()) &&  (str[index] - '0') * 10 + (str[index+1] - '0')  < 27 ){p2 = process(str , index + 2);}return p1 + p2;
}

动态规划

我们发现 递归函数中只依赖于一个参数index

int process(string& str , int index)

于是乎我们可以建立一张一维表

再通过递归函数看下依赖关系

 int p1 = process(str , index + 1);                                                                                            int p2 = 0;                     if (index + 1 < static_cast<int>(str.length()) &&  (str[index] - '0') * 10 + (str[index+1] - '0')  < 27 ){p2 = process(str , index + 2);}

我们能够得到下图

在这里插入图片描述

此时index + 2 不一定依赖 我们只需要加上一点判断条件即可

字符串贴纸

现在给定一个字符串str 给定一个字符串类型的数组arr 出现的字符全部是小写的英文字母

arr每一个字符串 代表一张贴纸 每种贴纸有无限多个 你可以把单个字符剪开使用 目的是拼出来str来返回需要至少多少张贴纸 返回一个最小值

例子: str = “babac” arr = {“ba” , “c” ,“abcd”}

至少需要两张贴纸 “abcd” “abcd”

递归版本

我们这么定义递归函数

int process(vector<string> stickers , string target)

这个函数的含义是 告诉我们贴纸的数量 告诉我们目标字符串 要求我们返回一个最小值

首先想base case

如果说target为空串了 此时我们只需要返回0即可

  if (target.size() == 0)    {    return 0;    }    

完整递归函数如下

int process(vector<string>& stickers , string target)                                                                           
{    if (target.size() == 0)    {    return 0;    }    int Min = INT32_MAX;    for (auto first : stickers)    {    string rest = strminus(target , first);    if (rest.length() != target.length())    {    Min = min(Min , process(stickers , rest));    }    }    Min = Min + (Min == INT32_MAX ? 0 : 1);    return Min;    
}    

我们设置一个int类型的值 Min 作为一个系统最大值

之后遍历整个贴纸数组 看看贴纸数组中的字符能不能减少目标target

如果能 我们就继续递归下去 让递归函数给我们一个最大值 如果不能我们就继续遍历下一个贴纸

最后我们看看Min是不是还是系统最大值 如果是就直接返回 如果不是 我们就让Min+1之后返回 (因为此时我们只是得到了去除第一张贴纸之后的最小值 所以说最后要加一)

动态规划

我们首先看原函数 影响它的参数是什么

int process(vector<string>& stickers , string target) 

我们发现只有一个target字符串在变化 但是我们对于字符串的变化是很难进行操作的

所以说对于这一题的动态规划我们采用记忆化搜索的方案

多加一个参数 map<string , int> 每次得到数据之前先把数据填进去即可

代码表示如下

int process(vector<string>& stickers , string target , map<string , int>& dp)    
{    if (dp.find(target) != dp.end())     {    return dp.find(target)->second;    }    if (target.size() == 0)    {    return 0;    }    int Min = INT32_MAX;    for (auto first : stickers)    {    string rest = strminus(target , first);    if (rest.length() != target.length())    {    Min = min(Min , process(stickers , rest , dp));    }    }    Min = Min + (Min == INT32_MAX ? 0 : 1);    dp[target] = Min;                                                                                                             return Min;    
} 

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

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

相关文章

记一次生产大对象及GC时长优化经验

最近在做一次系统整体优化,发现系统存在GC时长过长及JVM内存溢出的问题,记录一下优化的过程 面试的时候我们都被问过如何处理生产问题&#xff0c;尤其是线上oom或者GC调优的问题更是必问&#xff0c;所以到底应该如何发现解决这些问题呢&#xff0c;用真实的场景实操&#xff…

2015架构案例(五十一)

第5题 【说明】某信息技术公司计划开发一套在线投票系统&#xff0c;用于为市场调研、信息调查和销售反馈等业务提供服务。该系统计划通过大量宣传和奖品鼓励的方式快速积累用户&#xff0c;当用户规模扩大到一定程度时&#xff0c;开始联系相关企业提供信息服务&#xff0c;并…

批量执行insert into 的脚本报2006 - MySQL server has gone away

数据库执行批量数据导入是报“2006 - MySQL server has gone away”错误&#xff0c;脚本并没有问题&#xff0c;只是insert into 的批量操作语句过长导致。 解决办法&#xff1a; Navicat ->工具 ->服务器监控->mysql ——》变量 修改max_allowed_packet大小为512…

TCP/IP(七)TCP的连接管理(四)全连接

一 全连接队列 nginx listen 参数backlog的意义 nginx配置文件中listen后面的backlog配置 ① TCP全连接队列概念 全连接队列: 也称 accept 队列 ② 查看应用程序的 TCP 全连接队列大小 实验1&#xff1a; ss 命令查看 LISTEN状态下 Recv-Q/Send-Q 含义附加&#xff1a;…

【Java学习之道】日期与时间处理类

引言 在前面的章节中&#xff0c;我们介绍了Java语言的基础知识和核心技能&#xff0c;现在我们将进一步探讨Java中的常用类库和工具。这些工具和类库将帮助我们更高效地进行Java程序开发。在本节中&#xff0c;我们将一起学习日期与时间处理类的使用。 一、为什么需要日期和…

vsCode 忽略 文件上传

1 无 .gitignore 文件时&#xff0c;在项目文件右键&#xff0c;Git Bash 进入命令行 输入 touch .gitignore 生成gitignore文件 2 、在文件.gitignore里输入 node_modules/ dist/ 来自于&#xff1a;vscode git提交代码忽略node_modules_老妖zZ的博客-CSDN博客

k8s - Flannel

1.Flannel概念剖析 Flannel是 CoreOS 团队针对 Kubernetes 设计的一个覆盖网络&#xff08;Overlay Network&#xff09;工具&#xff0c;其目的在于帮助每一个使用 Kuberentes 的 CoreOS 主机拥有一个完整的子网。这次的分享内容将从Flannel的介绍、工作原理及安装和配置三方…

④. GPT错误:导入import pandas as pd库,存储输入路径图片信息存储错误

꧂ 问题最初꧁ 用 import pandas as pd 可是你没有打印各种信息input输入图片路径 print图片尺寸 大小 长宽高 有颜色占比>0.001的按照大小排序将打印信息存储excel表格文件名 表格路径 图片大小 尺寸 颜色类型 占比信息input输入的是文件就处理文件 是文件夹&#x1f4c…

44.ES

一、ES。 &#xff08;1&#xff09;es概念。 &#xff08;1.1&#xff09;什么是es。 &#xff08;1.2&#xff09;es的发展。 es是基于lucene写的。 &#xff08;1.3&#xff09;总结。 es是基于lucene写的。 &#xff08;2&#xff09;倒排索引。 &#xff08;3&#xf…

flutter 开发中的问题与技巧

一、概述 刚开始上手 flutter 开发的时候&#xff0c;总会遇到这样那样的小问题&#xff0c;而官方文档又没有明确说明不能这样使用&#xff0c;本文总结了一些开发中经常会遇到的一些问题和一些开发小技巧。 二、常见问题 1、Expanded 组件只能在 Row、Column、Flex 中使用 C…

GEE:基于GLDAS数据集分析土壤湿度的时间序列变化

作者:CSDN @ _养乐多_ 本篇博客将介绍如何使用Google Earth Engine(GEE)进行土壤湿度数据的分析。我们将使用NASA GLDAS(Global Land Data Assimilation System)数据集,其中包括了关于土壤湿度的信息。通过该数据集,我们将了解土壤湿度在特定区域和时间段内的变化,并生…

springboot vue 部署至Rocky(Centos)并自启,本文部署是若依应用

概述 1、安装nohup&#xff08;后台进程运行java&#xff09; 2、安装中文字体&#xff08;防止中文乱码&#xff09; 3、安装chrony&#xff08;保证分布式部署时间的一致性&#xff09; 5、安装mysql数据&#xff0c;迁移目录&#xff0c;并授权自启动&#xff1b; 6、安…

SpringBoot注解篇之@Validated

目录 前言Validated作用NotNull与NotBlank区别总结 前言 大家好&#xff0c;我是AK&#xff0c;在做新项目顺便整理SpringBoot相关内容&#xff0c;这里主要介绍下Validated注解的应用&#xff0c;减少核心业务逻辑中一些参数判断的代码。 Validated作用 Validated 是 Spring…

Linux友人帐之系统管理与虚拟机相关

一、虚拟机相关操作 1.1虚拟机克隆 虚拟机克隆是指将一个已经安装好的虚拟机复制出一个或多个完全相同的副本&#xff0c;包括虚拟机的配置、操作系统、应用程序等&#xff0c;从而节省安装和配置的时间和资源。 虚拟机克隆的主要用途有&#xff1a; 创建多个相同或相似的虚拟…

论文导读|八月下旬Operations Research文章精选:定价问题专题

编者按&#xff1a; ​ ​在“ Operations Research论文精选”中&#xff0c;我们有主题、有针对性地选择了Operations Research中一些有趣的文章&#xff0c;不仅对文章的内容进行了概括与点评&#xff0c;而且也对文章的结构进行了梳理&#xff0c;旨在激发广大读者的阅读兴…

win10搭建gtest测试环境+vs2019

首先是下载gtest&#xff0c;这个我已经放在了博客上方资源绑定处&#xff0c;这个适用于win10vs版本&#xff0c;关于liunx版本的不能用这个。 或者百度网盘链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/15m62KAJ29vNe1mrmAcmehA 提取码&#xff1a;vfxz 下…

asp.net会议预约管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net 会议预约管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语 言开发 asp.net 会议预约管理系统 二、…

miRNA测序数据生信分析——第四讲,未知物种的生信分析实例

miRNA测序数据生信分析——第四讲&#xff0c;未知物种的生信分析实例 miRNA测序数据生信分析——第四讲&#xff0c;未知物种的生信分析实例1. 下载测序数据2. 原始数据质控——软件fastqc3. 注释tRNA和rRNA&#xff0c;使用Rfam数据库——软件blast&#xff0c;Rfam_statisti…

Excel 插入和提取超链接

构造超链接 HYPERLINK(D1,C1)提取超链接 Sheet页→右键→查看代码Sub link()Dim hl As HyperlinkFor Each hl In ActiveSheet.Hyperlinkshl.Range.Offset(0, 1).Value hl.AddressNext End Sub工具栏→运行→运行子过程→提取所有超链接地址参考&#xff1a; https://blog.cs…

C++编程基础|多级指针

C编程基础|多级指针 一级指针二级指针三级指针多级指针的意义一维数组与数组指针二维数组与数组指针 在看代码时发现下面的内容 GridNodePtr *** GridNodeMap;struct GridNode; typedef GridNode* GridNodePtr;显而GridNodePtr是结构体GridNode首地址指针 那么GridNodeMap是什…