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

news2024/9/21 3:22:06

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

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

**特别需要注意的是 我们使用数组之前一定要进行初始化 不然很有可能会遇到一些意想不到的错误 比如说在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.coloradmin.cn/o/1080696.html

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

相关文章

易点易动让企业实现低值易耗品的智能化采购管理

对于企业而言&#xff0c;低值易耗品的采购和管理是一项重要的任务。然而&#xff0c;传统的采购管理方式往往繁琐且耗时&#xff0c;容易导致资源浪费和效率低下。为了解决这些问题&#xff0c;我们推出了易点易动采购管理系统&#xff0c;它以其高效、便捷和智能化的特点&…

怎样提取视频中的音频?分享一个一学就会的方法~

每次遇到视频中有好听的背景音乐都会想要保存下来&#xff0c;用于自己的视频创作。于是怎样单独提取视频中的音频部分就成了难题&#xff0c;今天教大家一个简单实用的视频提取音频办法&#xff0c;看完记得点赞收藏哦&#xff5e; 第一步&#xff1a;打开【音分轨】APP&#…

论文精读-Semi-Supervised Classification with Graph Convolutional Networks

Semi-Supervised Classification with Graph Convolutional Networks 目录 Semi-Supervised Classification with Graph Convolutional Networks一、摘要介绍二、图上的快速近似卷积2.1 谱图卷积 &#xff08;主要参考链接&#xff1a;[https://www.jianshu.com/p/35212baf6671…

100G SWDM4与100G BIDI SR光模块最新解决方案

随着数据中心和云计算网络的快速发展&#xff0c;高速度、高效率的数据传输需求不断增长。在这种背景下&#xff0c;100G SWDM4&#xff08;短波分复用技术&#xff09;和100G BIDI光模块作为两种先进的光模块技术&#xff0c;得到了广泛应用。下面我们来看看这两种光模块的应用…

基于Springboot实现垃圾分类网站管理系统项目【项目源码+论文说明】

基于Springboot实现垃圾分类网站管理系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个垃圾分类网站 &#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述垃…

Fiddler抓包常用功能介绍

Fiddler中常用的功能如下&#xff1a; 停止抓包清空会话窗内容过滤请求解码设置断点 一. 停止抓包 二. 清空会话窗 方法一&#xff0c;工具栏工具&#xff1a; 方法二&#xff0c;命令行形式&#xff1a; 当然&#xff0c;命令行工具也还支持其他命令的输入&#xff0c;这里不…

CDN:加速型与高防型的不同

网络世界中的 CDN&#xff0c;也就是内容分发网络&#xff08;Content Delivery Network&#xff09;&#xff0c;是当今互联网体验的潜在改变者。它的作用原理可不止于让网页快一点&#xff0c;让我们深入了解一下。 CDN基本原理是通过在世界各地分布的节点服务器&#xff0c;…

视频剪辑达人秘籍:快进时光,精准调整多个视频的播放速度!

在创作视频的过程中&#xff0c;有时候我们可能需要将多个视频进行剪辑和调整&#xff0c;以展现所需的效果和节奏。而其中一个常见的需求就是快进视频&#xff0c;让观众更快地体验内容&#xff0c;提升观影体验。不用担心&#xff0c;我们将教你如何在众多视频中将视频播放速…

2023年【G2电站锅炉司炉】考试资料及G2电站锅炉司炉新版试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年G2电站锅炉司炉考试资料为正在备考G2电站锅炉司炉操作证的学员准备的理论考试专题&#xff0c;每个月更新的G2电站锅炉司炉新版试题祝您顺利通过G2电站锅炉司炉考试。 1、【多选题】《中华人民共和国特种设备安…

微信小程序点击事件bindtap传参

微信小程序点击事件bindtap传参 错误写法正确写法 微信小程序bindtap点击事件如何传参 错误写法 wxml页面 <view class"fix-add" bind:tap"goPage(/family_pages/form_electricity/form_electricity)"><van-icon name"add" /> <…

PMP证书烂大街?过来人理性分析

&#xff08;1&#xff09;究竟是不是智商税&#xff1f; “PMP证书是智商税&#xff0c;报名费这么贵&#xff0c;考了又没啥用” “又不像软考能评职称&#xff0c;地方补贴待遇好&#xff01;考了干嘛&#xff1f;” “考了就能年薪50W&#xff1f;就能当项目经理&#x…

【面试经典150 | 哈希表】有效的字母异位词

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;排序方法二&#xff1a;哈希数组 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于…

上海-华为全联接大会|竹云受邀参加华为云ROMAConnect行业生态联盟成立联合发布会

2023年9月22日&#xff0c;在上海举办的华为全联接大会上&#xff0c;竹云作为华为云全方位合作伙伴代表&#xff0c;受邀参加华为云ROMAConnect行业生态联盟成立联合发布会。华为云PaaS服务产品部副部长张甲磊以及联盟主要成员企业出席发布仪式&#xff0c;共同见证华为云ROMA…

项目结构目录说明--treer的使用

模块化项在模块比较多的时候&#xff0c;需要整理一份各模块的说明&#xff0c;怎么能够直观的和项目对比看比较清晰呢&#xff0c;有没有一种直观体现方式呢&#xff0c;有的&#xff0c;请看本篇文章足够。 效果图&#xff1a; 需要treer即可实现。 安装treer 在项目跟目录…

手机cpu架构查看及armeabi、armeabi-v7a、arm64-v8a及x86等说明

一、如何查看cpu加购 winR&#xff0c;输入cmd 填下指令如下 adb shell getprop ro.product.cpu.abi 二、架构描述 1.armeabiv-v7a: 第7代及以上的 ARM 处理器。2011年15月以后的生产的大部分Android设备都使用它. 2.arm64-v8a: 第8代、64位ARM处理器&#xff0c;很少设备&a…

Git如何上传代码至GitHub

GitHub是一个面向开源及私有软件项目的托管平台&#xff0c;因为只支持Git作为唯一的版本库格式进行托管&#xff0c;故名GitHub。GitHub拥有1亿以上的开发人员&#xff0c;400万以上组织机构和3.3亿以上资料库。 今天&#xff0c;详细介绍如何将文件通过Git上传至GitHub。 如…

21字符串-简单操作

目录 字符串匹配 重要概念 BF算法 RK算法 LeetCode之路——344. 反转字符串 分析 LeetCode之路——541. 反转字符串 II 分析 字符串匹配 字符串匹配的算法很多&#xff0c;常见的有BF&#xff08;Brute Force&#xff09;、RK&#xff08;Rabin-Karp&#xff09;这两种…

3D开发工具HOOPS助力Eleven Dynamics加速开发QA自动化平台

Nexos平台提供强大的可视化功能&#xff0c;并将整体测量时间减少80%。 2021年10月19日&#xff0c;俄勒冈州本德市&#xff08;Newswire.com&#xff09;——工程软件开发工具包的领先供应商Tech Soft 3D今天宣布&#xff0c;Eleven Dynamics是一家位于瑞士的初创公司&#x…

CPU的执行流程

CPU的执行流程 取指令&#xff08;Instruction Fetch&#xff09;&#xff1a;CPU 从程序存储器&#xff08;通常是内存&#xff09;中获取要执行的下一条指令。这个过程包括以下步骤&#xff1a; CPU 从程序计数器&#xff08;Program Counter&#xff0c;PC&#xff09;中获…

1682653-80-0,四嗪染料试剂Tetrazine PEG5 NHS,四嗪五聚乙二醇活性脂

产品亮点&#xff1a;Tetrazine PEG5 NHS ester&#xff08;四嗪五聚乙二醇活性脂&#xff09;是一种高效能的生物活性化合物&#xff0c;拥有卓越的生物相容性和水溶性&#xff0c;用途广泛。CAS号&#xff1a;1682653-80-0&#xff0c;中文名&#xff1a;四嗪五聚乙二醇活性脂…