当前位置: 首页 > news >正文

代码随想录算法训练营第五十一天|LeetCode72 编辑距离、LeetCode647 回文子串、LeetCode516 最长回文子序列、动态规划的小总结

题1:

指路:72. 编辑距离 - 力扣(LeetCode)
思路与代码:

关于dp数组的定义,我们定义一个二维数组dp[i][j],其含义为以i-1为结尾的字符串word1和以j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。关于递推公式,如果数组1和数组2中内容相等,此时无须做任何操作,就等于下标为i-1和j-1的编辑距离,也就是dp[i][j]=dp[i-1][j-1]。当数组1和数组2中内容不同时,此时有三种操作,增、删、改。注意:当word1和word2中内容不相同时,不一定是单单改变其中一个变成另一个,也可以选择两者同时改变向对方靠近。删除word1的一个字符是dp[i-1][j]+1,替换字符为dp[i-1][j-1]+1,删除word2中字符(相对于word1为增加字符)即为dp[i][j-1]+1,取最小值即为 dp[i][j] = min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}) + 1。那么在初始化环节,dp[i][0]的含义为以下标i-1为结尾的字符串word1和空字符串word2的最近编辑距离为dp[i][0],得到dp[i][0]=i,同理dp[0][j]=j。对于遍历顺序,很显然是从上到下从左到右,最后打印即可。代码如下:

class Solution {
public:int minDistance(string word1, string word2) {vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;for (int i = 1; i <= word1.size(); i++) {for (int j = 1; j <= word2.size(); j++) {if (word1[i - 1] == word2[j - 1]) {dp[i][j] = dp[i - 1][j - 1];}else {dp[i][j] = min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}) + 1;}}}return dp[word1.size()][word2.size()];}
};

题2:

指路:647. 回文子串 - 力扣(LeetCode)
思路与代码:

定义一个数组dp[i][j],其含义为在i和j的范围内如果i和j对应的值相等且子串如果是回文串那么这个以i和j为范围的字符串就是回文子串,其中分为三种情况,首先,i和j相等,那么显然这个字符串就是只有一个字符的字符串,肯定是一个回文串,遇到符合条件的回文串时计数器加1;其次如果i和j相差为1,也就是i和j相邻,此时如果s[i]等于s[j]那么这也是一个回文字符串;最后一种情况为i和j相差大于1,也就是它们之中有一个子串,此时将i定义为数组始位置j定义为尾位置,在判断s[i]等于s[j]后,再进一步将i和j各往前移位一位,也就是i+1和j-1的位置,如果也成立继续判断得到回文子串的判断。注意,我们在i和j位置的数值也要判断的是i+1和j-1的位置的数值,那么在二维数组中对应的位置就是[i,j]的左下方位置,换句话来说,由左下方向右上方判断,也就是从左到右从下往上循环。最后输出即可。

class Solution {
public:int countSubstrings(string s) {if (s.size() <= 1) return s.size();vector<vector<bool>> dp(s.size(), vector<bool>(s.size(), false));int result = 0;for (int i = s.size() - 1; i >= 0; i--) {for (int j = i; j < s.size(); j++) {if (s[i] == s[j]) {if (j - i <= 1) {result++;dp[i][j] = true;}else if (dp[i + 1][j - 1]) {result++;dp[i][j] = true;}}}}return result;}
};

题3:

指路:516. 最长回文子序列 - 力扣(LeetCode)
思路与代码:

本题与上题的区别在于子串和子序列的区别,子串须连续,子序列则不需要。定义一个数组dp[i][j],其含义为字符串s[i, j]范围内最长的回文子序列的长度为d[i][j]。递推公式中,依旧是回文,判断s[i]与s[j]的相等状况就好。如果二者相同那么dp[i][j]=dp[i+1][j-1]+2(加2是因为首尾元素也是回文子序列的一部分),如果二者不相同则说明首尾元素不能同时加入子序列的队伍,那么尝试首尾元素分开添加,取较大值即可,即dp[i][j]=max(dp[i+1][j], dp[i][j-1])。这里的遍历顺序如上题所言,从下往上从左往右,最后打印即可。代码如下:

class Solution {
public:int longestPalindromeSubseq(string s) {vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));for (int i = 0; i < s.size(); i++) dp[i][i] = 1;for (int i = s.size() - 1; i >= 0; i--) {for (int j = i + 1; j < s.size(); j++) {if (s[i] == s[j]) {dp[i][j] = dp[i + 1][j - 1] + 2;}else {dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);}}}return dp[0][s.size() - 1];}
};

动态规划的小总结:

呼~动态规划终于告一段落了,感觉比起子序列问题我更喜欢股票类问题。但是无外乎就五步,定义dp数组及其定义,推断递推公式,初始化dp数组,确定遍历顺序最后打印dp数组。好累,先这样。

http://www.lryc.cn/news/385072.html

相关文章:

  • sessionStorage 能在多个标签页之间共享数据吗?
  • 鸿蒙期末项目(完结)
  • 【Linux】对共享库加载问题的深入理解——基本原理概述
  • easyui的topjui前端框架使用指南
  • Java中的程序异常处理介绍
  • Gradle学习-3 Gradle插件
  • 百度文心智能体,创建属于自己的智能体应用
  • 【软件测试】白盒测试与接口测试详解
  • 【SpringBoot Web框架实战教程】03 SpingBoot 获取 http 请求参数
  • Mac14.1.2 M1芯片免费读写ntfs硬盘-亲测有效,免费!!!
  • 手写SpringMVC之ApplicationContextListener
  • Paimon 在汽车之家的业务实践
  • 2024-06-27 问AI: 介绍一下 LLM building process
  • 猫也有自动厕所上了吗?自费分享好用的智能猫砂盆,看完不亏。
  • 《分析模式》漫谈07-怎样把一张图从不严谨改到严谨
  • 纯干货丨知乎广告投放流程和避坑攻略
  • mac 安装mysql启动报错 ERROR!The server quit without update PID file
  • TypeScrip环境安装与基础
  • 6.27学习总结
  • 选择第三方软件测试机构做验收测试的好处简析
  • 【图书推荐】CPython设计与实现“适合所有Python工程师阅读的书籍”
  • 原创作品—医疗行业软件界面UI、交互设计
  • [C++深入] --- vector容器浅析
  • 用MySQL和navicatpremium做一个项目—(财务管理系统)。
  • Jenkins教程-5-gitee自动化测试任务构建
  • CAN-bus总线在冷链运输中的应用
  • Vue 与 React 区别
  • docker+[nginx] 部署nacos2.x 集群
  • Linux学习第54天:Linux WIFI 驱动:蓝星互联
  • 芯片后端之 PT 使用 report_timing 产生报告如何阅读