算法 | 动态规划 | 系列题目讲解(思路记录part.1)

news/2024/5/21 0:35:31/文章来源:https://blog.csdn.net/weixin_61432764/article/details/128902364

文章目录

    • 字符串分割
    • 三角矩阵
    • 路径总数
    • 最小路径和

字符串分割

  • 问题描述

给定一个字符串和一个词典dict,确定s是否可以根据词典中的词分成
一个或多个单词。
比如,给定
s = “leetcode”
dict = [“leet”, “code”]
返回true,因为"leetcode"可以被分成"leet code"

题目链接

(说明一下,F{i)中的i是指字符串的前i个字符,和str[i]不同,这里的i是数组下标,所以str[0, i]是指字符串的前i + 1个字符)

首先确定状态,F(i)表示字符串的前i个字符能否被分割,用true和false表示。现在要确定的是如何推导F(i)?假设字符串为str,我们要确定str的前i个字符是否可以分割,分解子问题,用j分解字符串,确定str[0, j - 1]与str[j, i - 1]是否可以分割,它们可以分割str就可以分割。因为str[0, j - 1]是字符串的前j个字符,我们可以通过F(j)获取其能否被分割(j肯定比i小,F(j)的状态肯定已经更新过了),至于[j, i - 1]区间的字符,就要遍历字典,查找str[j, i - 1]是否在字典中。如果两者的结果都是true,那么str的前i个字符就是可以分割的。

既然F(i)表示的是字符串的前i个字符能否被分割,那么F(0)是什么?我们将其设置为true,字符串的前0个字符是不存在的,但是我们需要F(0)作为初始状态进行递推。假设字符串的长度为size,那么最后只要返回字符串的前size个字符能否被分割,即F(size)就可以了

bool wordBreak(string s, unordered_set<string> &dict) {vector<bool> can_break(s.size() + 1, false);can_break[0] = true;// 从第1个字符开始到最后一个字符结束,确定状态for (size_t i = 1; i <= s.size(); ++i){// 从j分割字符串,j表示字符串的第j个字符,不是数组下标for (size_t j = 0; j <= i; ++j){// 前j个字符可以分割,并且j + 1到i的字符也可以分割if (can_break[j] && dict.count(s.substr(j, i - j))){can_break[i] = true;break;}}}//  返回数组的最后一个位置return can_break[s.size()];
}

其中,在字典中查找会用到count接口,获取字符串的子串会用到substr接口,这些接口可以在这里查询

三角矩阵

  • 问题描述

给定一个三角矩阵,找出自顶向下的最短路径和,每一步可以移动到下一行的相邻数字。

题目链接

在这里插入图片描述

题目会给定一个二维数组,用二维数组表示一个三角形。首先确定状态,F(i, j)表示从顶点开始到i行j列的点的最短路径,求出从顶点到最后一行所有点的最短路径,在其中选择一个最小的,就是自顶向下的最短路径和。现在要确定的是如何推导F(i, j)?题目说每一步可以移动到下一行的相邻数字,也就是可以从dp[i - 1, j -1]或者dp[i - 1, j]移动到dp[i, j],从这两条路径中选择较小的那条,即F(i, j) = min(F(i - 1, j - 1), F(i - 1, j)) + triangle[i][j]。比如要到达5,可以从3到5,也可以从4到5,我们要从这两条路径中找出较小的那条(在dp数组中查找),然后再加上自己的值,就是从顶点到5的最短路径。更新完dp数组,在数组的最后一行查找得到的最小值就是最后的答案

但是数组的初始状态需要格外注意,首先是顶点到顶点的最短路径就是自己,所以dp[0][0]为0。其次是三角矩阵的左边界和右边界,比如要达到4,只能从6走,达到4的路径只有一条,顶点2->3->6->4,同理边界上所有的点都是这样,此时我们的状态转移方式对这些点不再适用,我们需要单独处理这些点,它们的最短路径就是从顶点不断的累加到自己。

int minimumTotal(vector<vector<int> > &triangle) {size_t row = triangle.size();// 数组初始化for (size_t i = 1; i < row; ++i){triangle[i][0] += triangle[i - 1][0];triangle[i][triangle[i].size() - 1] += triangle[i - 1][triangle[i - 1].size() - 1];}// 更新数组for (size_t i = 1; i < row; ++i){for (size_t j = 1; j < triangle[i].size() - 1; ++j){triangle[i][j] += min(triangle[i - 1][j - 1], triangle[i - 1][j]);}}// 查找最小路径int ret = triangle[row - 1][0];for (size_t i = 0; i < triangle[row - 1].size(); ++i){ret = min(ret, triangle[row - 1][i]);}return ret;
}

写这道题时,最难的地方不是转移方程的推导,而是数组边界的确定,左右边界的更新,i,j作为数组下标具体的范围在哪?这些都要仔细考虑。

除了自顶向下的更新数组,我们还可以自底向上更新,用F(i, j)表示i行j列的点到底边的最短路径,不再是从顶点到i行j列的点的最短路径了。要更新F(i, j)就要考虑F(i + 1, j)与F(i + 1, j + 1),因为i行j列的点到底边只经过了这两个点,所以状态转移方程F(i, j) = min(F(i + 1, j), F(i + 1, j + 1)) + triangle(i, j),并且每一次对i行的更新都要用到i + 1行的数据(转移方程的右边都是i + 1),所以我们需要自底向上开始更新,使i + 1行的数据满足我们设定的状态,再更新i行的数据。

那么初始状态是怎样的?因为最后一行到底边的最短距离就是自己本身,所以最后一行的状态已经确定好了,我们从倒数第二行开始更新数组,并且左右边界也不需要特地更新,因为这些点已经满足了我们的状态转移方程。最后我们只要返回F(0, 0)即可,F(0, 0)为从顶点到底边的最短距离

int minimumTotal(vector<vector<int> > &triangle) {for (int i = triangle.size() - 2; i >= 0; --i){for (int j = 0; j < triangle[i].size(); ++j){triangle[i][j] += min(triangle[i + 1][j], triangle[i + 1][j + 1]);}}return triangle[0][0];
}

很显然,这样的解法更简单

路径总数

  • 问题描述

在一个m*n的网格的左上角有一个机器人,机器人在任何时候只能向下或者向右移动,机器人试图到达网格的右下角,有多少可能的路径。

题目链接

同样的,先确定题目的状态F(i, j),F(i, j)表示从左上角到i行j列的点的总路径数。那么F(i, j)要怎么推导呢?从题目中我们得知,机器人只能向下或者向右移动,也就是说要走到[i, j],必须要经过[i - 1, j]或者[i, j - 1],所以F(i, j) = F(i - 1, j) + F(i, j - 1),到[i, j]的路径数等于[i - 1, j]加上[i, j - 1]的路径总和。状态转移方程确定了,现在要确定的就是题目的初始条件,用来更新的dp数组中,由于第一行和第一列的所有点不满足该状态转移方程,所以我们应该先处理这些点,从左上角到这些点的路径只有一条,要么直接向右走,要么直接向下走,所以dp数组的第一行和第一列被初始化为1。最后返回F(m, n)就行了

int uniquePaths(int m, int n) {vector<vector<int>> dp(m, vector<int>(n));// dp数组的初始化    for (size_t i = 0; i < m; ++i){dp[i][0] = 1;}for (size_t i = 0; i < n; ++i){dp[0][i] = 1;}// dp数组的更新for (size_t i = 1; i < m; ++i){for (size_t j = 1; j < n; ++j) {dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}}return dp[m - 1][n - 1];
}

最小路径和

  • 问题描述

给定一个m*n的网格,网格用非负数填充,找到一条从左上角到右下角的最短路径(只能向下或者向右移动)。

题目链接
和路径总数那题类似,先确定状态,F(i, j)表示从左上角到第i行j列的最小路径和,当i和j指向右下角时,F(i, j)就是从左上角到右下角的最短路径。现在要确定的是状态转移方程,F(i, j) = min(F(i - 1, j), F(i, j - 1)) + array[i, j]:从唯二到达[i, j]的路径中,选择一条更小的,并加上到[i, j]的值。然后就是确定初始状态,第一行与第一列的点只有一种方向可以到达,直接向右或者直接向下走就行,所以在更新dp数组前先更新这些点

int minPathSum(vector<vector<int> >& grid) {size_t row = grid.size();size_t col = grid[0].size();// dp数组的初始化for (size_t i = 1; i < row; ++i){grid[i][0] += grid[i - 1][0];}for (size_t i = 1; i < col; ++i){grid[0][i] += grid[0][i - 1];}// dp数组的更新for (size_t i = 1; i < row; ++i){for (size_t j = 1; j < col; ++j){grid[i][j] += min(grid[i - 1][j], grid[i][j - 1]);}}return grid[row - 1][col - 1];
}

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

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

相关文章

吾剑未尝不利,国内Azure平替,科大讯飞人工智能免费AI语音合成(TTS)服务Python3.10接入

微软Azure平台的语音合成(TTS)技术确实神乎其技&#xff0c;这一点在之前的一篇&#xff1a;含辞未吐,声若幽兰,史上最强免费人工智能AI语音合成TTS服务微软Azure(Python3.10接入)&#xff0c;已经做过详细介绍&#xff0c;然则Azure平台需要信用卡验证&#xff0c;有一定门槛&…

基于Apache Maven构建多模块项目

title: 基于Apache Maven构建多模块项目 date: 2022-04-10 00:00:00 tags: Apache Maven多模块 categories:Maven 介绍 多模块项目由管理一组子模块的聚合器 POM 来构建。在大多数情况下聚合器位于项目的根目录中&#xff0c;并且必须是 pom 类型的项目。子模块是常规的 Mave…

CNN网络:ResNet(四)

ResNet论文[https://arxiv.org/pdf/1512.03385.pdf]。RestNet网络结构ResNet在2015年被提出&#xff0c;在ImageNet比赛classification任务上获得第一名&#xff0c;因为它“简单与实用”并存&#xff0c;之后很多方法都建立在ResNet50或者ResNet101的基础上完成的&#xff0c;…

手机逻辑系统(2)---逻 辑 音 频 电 路

第二节 逻 辑 音 频 电 路 逻辑音频电路在手机电路中占有重要的地位,它是手机系统的心脏。 逻辑音频电路包含无线通信呼叫处理、音频处理、数字语音处理、射频逻辑接口电路、各种射频功能控制、电源管理和用户接口模组等。 任何一部手机的逻辑音频电路部分都包含以上的一些功能…

1.2.4存储结构-磁盘管理:磁盘优化分布存储、磁盘优化分布存储例题

1.2.4存储结构-磁盘管理&#xff1a;磁盘优化分布存储、磁盘优化分布存储例题磁盘优化分布存储磁盘优化分布存储 假设某磁盘的每个磁道划分成11个物理块&#xff0c;每块存放1个逻辑记录。逻辑记录R0&#xff0c;R1&#xff0c;…&#xff0c;R9&#xff0c;R10存放在同一个磁…

将U盘制作为启动盘

将U盘制作为启动盘 制作之前需要先保证U盘中没有重要的文件&#xff0c;因为制作时会将已有文件删除 1 安装制作软件【wePE】 ①官网选择对应PE版本下载安装 官网下载地址:http://www.wepe.com.cn IT天空的U盘装机助理&#xff1a;https://www.itiankong.net/thread-357573-1…

Ubuntu18 安装python3.7及多版本切换

1.安装3.7添加源sudo add-apt-repository ppa:deadsnakes/ppa检查更新sudo apt-get update 安装python3.7sudo apt-get install python3.72.使用 update-alternatives 来为整个系统更改Python 版本查看python替代版本信息~$ update-alternatives --display python但是结果为upd…

数字化发展趋势:打破企业边界,实现产业互联

据中欧商业在线发布的《2022未来管理人才白皮书》显示&#xff0c;在参加调研的1000家企业中&#xff0c;有77%的企业已经在公司业务中运用了数字化技术&#xff1b;更有7%的企业表示将在更深层面推进数字化转型工作。 当企业在业务层面完成数字化转型&#xff0c;下一步会走向…

知识图谱简介

知识图谱简介 知识图谱&#xff0c;是结构化的语义知识库&#xff0c;用于迅速描述物理世界中的概念及其相互关系&#xff0c;通过知识图谱能够将Web上的信息**、数据以及链接关系聚集为知识&#xff0c;使信息资源更易于计算、理解以及评价&#xff0c;并能实现知识的快速响应…

Keil中代码的颜色设置 ( 很 全 )[通俗易懂](转载)

https://cloud.tencent.com/developer/article/2081534Keil中代码的颜色设置 ( 很 全 )[通俗易懂]发布于2022-08-25 12:26:13阅读 1.8K0大家好&#xff0c;又见面了&#xff0c;我是你们的朋友全栈君。因为长时间要编程&#xff0c;对于keil上的黑字白底&#xff0c;如果看久了…

Python实现的通讯录

"为何表情&#xff0c;要让这世界安排&#xff1f;"诶&#xff0c;我们也对python的一些基础语法有了一定能的了解了。并且在这基础上&#xff0c;学习了python中的文件操作&#xff0c;那么有了这些东西以后啊&#xff0c;我们能做什么呢&#xff1f;或许对很多数据…

揭秘PPTC(自恢复保险丝)的四大使用原则

PPTC自恢复保险丝有贴片式以及插件式两种&#xff0c;封装形式多样&#xff0c;型号齐全&#xff0c;那么&#xff0c;在使用过程中&#xff0c;应该要注意什么&#xff1f;你知道吗&#xff1f;接下来&#xff0c;优恩小编将为你揭秘PPTC(自恢复保险丝)的四大使用原则。一、规…

Spring boot项目开发实战一(环境搭建)

技术栈选型 最近在实习好久没时间做过项目了&#xff0c;本次将借用公司的技术完成一个基于spring boot的实战项目&#xff0c;同时也巩固spring的相关知识。项目大体是一个后台管理系统&#xff0c;没有前台&#xff0c;用于数据分析和可视化。如下是初步的可视化界面&#x…

MySQL8.0 集群搭建

文章目录环境准备安装 MySQL 8.0配置主服务配置从服务器主从复制&#xff1a;即主服务器上的所有操作&#xff08;创建库&#xff0c;修改表等&#xff09;会被同步到从服务器上&#xff0c;但是在从服务器上的操作不会进入到主服务器中 环境准备 两台服务器&#xff0c;一主…

【Classical Network】Xception

文章目录深度可分离卷积Inception发展GoogleNetInception Networkinception V1inception V2inception V3inception V4Xception参考文章 经典卷积架构的PyTorch实现&#xff1a;Xception 参考文章 卷积神经网络结构简述&#xff08;二&#xff09;Inception系列网络 github 项目…

Springboot扩展点之InstantiationAwareBeanPostProcessor

前言前面介绍了Springboot的扩展点之BeanPostProcessor&#xff0c;再来介绍另一个扩展点InstantiationAwareBeanPostProcessor就容易多了。因为InstantiationAwareBeanPostProcessor也属于Bean级的后置处理器&#xff0c;还继于BeanPostProcessor&#xff0c;因此Instantiatio…

【Spring Cloud Alibaba】(二)微服务调用组件Feign原理+实战

系列目录 【Spring Cloud Alibaba】&#xff08;一&#xff09;微服务介绍 及 Nacos注册中心实战 本文目录系列目录前言什么是RPC&#xff1f;Feign和OpenFeign都是什么&#xff1f;HTTP调用 vs Feign(RPC)调用单独使用Feign实战Feign核心源码解读Feign整体设计架构Spring Clo…

PyQt5学习 阶段一

前言&#xff1a;PyQt5介绍PyQt是基于Digia公司强大的图形程序框架Qt的Python接口&#xff0c;由一组Python模块构成&#xff0c;它是一个创建GUI应用程序的工具包&#xff0c;由Phil Thompson开发。PyQt5的基本类&#xff1a;官方提供的帮助网址&#xff1a;https://www.river…

每天10个前端小知识 【Day 8】

前端面试基础知识题 1. Javascript中如何实现函数缓存&#xff1f;函数缓存有哪些应用场景&#xff1f; 函数缓存&#xff0c;就是将函数运算过的结果进行缓存。本质上就是用空间&#xff08;缓存存储&#xff09;换时间&#xff08;计算过程&#xff09;&#xff0c; 常用于…

macbook M1 Homebrew配置导致本机的Kafka启动失效

笔者想在macbook M1上通过Homebrew安装Kafka 整体流程为&#xff1a; 安装kafka brew install kafka 启动zookeeper brew services start kafka启动kafka brew services start kafka启动provider&#xff0c;创建一个jxztest的主题 kafka-console-producer --bootstrap-server…