算法系列--动态规划--回文子串系列

💕"我们好像在池塘的水底,从一个月亮走向另一个月亮。。"💕
作者:Mylvzi
文章主要内容:算法系列–动态规划–回文子串系列
在这里插入图片描述

今天为大家带来的是算法系列--动态规划--回文子串系列(1),本文重点掌握如何快速判断一个字符串是否是回文子串

一.回文子串(引入)

先来看力扣上这道题目:回文子串

在这里插入图片描述

1.利用动态规划的思想解决这道题目(重点)

回文子串其实是子数组的一种,只不过这里将数字换为字符而已,所以回文子串的问题也可以使用动态规划的思想解决,但是这个状态表示相较于常规的字符数组有些不同,在回文子串问题中,我们需要创建一个二维的dp表去存储所有子串是否是回文子串的信息,也就是说这个dp表是一个`boolean``类型的数组

首先如何得到所有的子字符串呢?很简单,两层for循环就能解决这个问题
在这里插入图片描述
注意:单独一个字符也算子字符串!!!

明确上述前置知识之后,下面讲解如何利用动态规划的思想解决回文子串问题

  1. 状态表示:dp[i][j]表示以i下标为起始位置,j下标为结束位置的子字符串是否是回文子串的信息

  2. 状态转移方程:
    在这里插入图片描述

  3. 初始化:无需初始化,越界的条件被特别判断了,不会出现越界的情况
    在这里插入图片描述

  4. 填表顺序:从下往上填
    在这里插入图片描述

  5. 返回值:dp[i][j]为true的数目

代码实现:

class Solution {public int countSubstrings(String s) {char[] ss = s.toCharArray();// 转化为字符数组int ret = 0;// 记录dp表中true的数目int n = s.length();boolean[][] dp = new boolean[n][n];for(int i = n - 1; i >= 0; i--) {// 从后往前遍历字符串for(int j = i; j < n; j++) {if(ss[i] == ss[j])// 只用判断相等的情况,不相等就是默认值false;dp[i][j] = i + 1 < j ? dp[i + 1][j - 1] : true;ret += dp[i][j] == true ? 1 : 0;}}return ret;}
}

如果使用动态规划,时间复杂度,空间复杂度均为为O(N^2)回文子串问题使用动态规划虽然不是最优解,但是可以实现一个非常重要的功能将所有子串是否是回文子串的信息,存储到dp表之中,最优解还有中心拓展算法马拉车算法

中心拓展算法的实现:

链接:https://leetcode.cn/problems/palindromic-substrings/solutions/379987/hui-wen-zi-chuan-by-leetcode-solution/
来源:力扣(LeetCode)

class Solution {public int countSubstrings(String s) {int n = s.length(), ans = 0;for (int i = 0; i < 2 * n - 1; ++i) {int l = i / 2, r = i / 2 + i % 2;while (l >= 0 && r < n && s.charAt(l) == s.charAt(r)) {--l;++r;++ans;}}return ans;}
}

2.最长回文子串

链接:
https://leetcode.cn/problems/longest-palindromic-substring/

分析:

还是利用和上道题一样的动态规划思想,在本题中需要得到的是最长的回文子串,在回文子串的动态规划里,我们已经保存了所有的回文子串的信息,只要判断出来时回文子串,就更新一下长度即可

可以使用一个数组ret来记录字符串的起始结束位置

代码:

class Solution {public String longestPalindrome(String s) {char[] ss = s.toCharArray();int n = s.length();boolean[][] dp = new boolean[n][n];// 创建dp表int[] ret = new int[2];// 记录字符串的起始位置和结束位置for(int i = n - 1; i >=0; i --){for(int j = i; j < n; j++) {if(ss[i] == ss[j])dp[i][j] = i + 1 < j ? dp[i + 1][j - 1] : true;if(dp[i][j] == true) {if(j - i > ret[1] - ret[0]) {ret[0] = i;ret[1] = j;}}}}return s.substring(ret[0],ret[1] + 1);// 注意是"左闭右开"}
}

3.回⽂串分割IV

链接:
https://leetcode.cn/problems/palindrome-partitioning-iv/description/
在这里插入图片描述

分析:

  • 其实题目的意思很简单,就是判断字符串s能否分割为三个回文子串,最直观的想法就是暴力求解+判断是否是回文子串,而判断是否是回文子串已经在上面做过了
    在这里插入图片描述
    代码:
class Solution {public boolean checkPartitioning(String s) {char[] ss = s.toCharArray();// 转化为字符数组int ret = 0;// 记录dp表中true的数目int n = s.length();boolean[][] dp = new boolean[n][n];// 使用dp表保存所有的子字符串的信息for(int i = n - 1; i >= 0; i--) {// 从后往前遍历字符串for(int j = i; j < n; j++) {if(ss[i] == ss[j])// 只用判断相等的情况,不相等就是默认值false;dp[i][j] = i + 1 < j ? dp[i + 1][j - 1] : true;}}// 将字符串s分割为三个子字符串,分别判断是否是回文字符串for(int i = 1; i < n - 1; i++) {for(int j = i; j < n - 1; j++) {if(dp[0][i - 1] && dp[i][j] && dp[j + 1][n - 1])return true;}}return false;}
}

4.分割回⽂串II

链接:
https://leetcode.cn/problems/palindrome-partitioning-ii/description/
在这里插入图片描述
分析:

其实这道题和单词拆分很像,单词拆分中需要我们遍历整个字符串,判断对应的单词是否存在于字典之中,本题也是需要遍历整个字符串,判断对应的子字符串是否是回文子串,而判断是否是回文子串已经在上面介绍过

在这里插入图片描述

代码:

class Solution {public int minCut(String s) {char[] ss = s.toCharArray();// 转化为字符数组int ret = 0;// 记录dp表中true的数目int n = s.length();boolean[][] predp = new boolean[n][n];for(int i = n - 1; i >= 0; i--) {// 从后往前遍历字符串for(int j = i; j < n; j++) {if(ss[i] == ss[j])// 只用判断相等的情况,不相等就是默认值false;predp[i][j] = i + 1 < j ? predp[i + 1][j - 1] : true;}}// 下面是正题int[] dp = new int[n];for(int i = 0; i < n; i++) dp[i] = Integer.MAX_VALUE;// 初始化为最大值for(int i = 0; i < n; i++) {if(predp[0][i] == true) dp[i] = 0;// 0->i为回文串else {// 0->i不是回文串for(int j = 1; j <= i; j++) {if(predp[j][i]) dp[i] = Math.min(dp[i],dp[j - 1] + 1);}}}return dp[n - 1];}
}

5.最长回文子序列

链接:
https://leetcode.cn/problems/longest-palindromic-subsequence/

分析:

最先想到的状态表示就是以i位置为结尾字符串中的最长的回文子序列的长度,但是进一步分析发现此状态表示无法推导出状态转移方程,原因在于我们根本不能确定回文子序列,所以要更换一个状态表示

经过上述分析发现仅仅固定一个位置去表示字符串无法确定其回文子序列,所以需要两个下标来确定一个字符串(是不是和回文子串很像?),然后再去推导状态转移方程,只不过这里的状态相较于连续的子串更多一些,下面是详细的分析过程
在这里插入图片描述

代码:

class Solution {public int longestPalindromeSubseq(String s) {char[] ss = s.toCharArray();// 转化为字符数组int n = s.length();// 创建dp表int[][] dp = new int[n][n];dp[0][0] = dp[n - 1][n - 1] = 1;// 初始化int ret = 0;// 记录最大值for(int i = n -1; i >=0; i--) {for(int j = i; j < n; j++) {if(ss[i] == ss[j]) {if(i == j) dp[i][j] = 1;else if(i + 1 == j) dp[i][j] = 2;else dp[i][j] = dp[i + 1][j - 1] + 2;}else {dp[i][j] = Math.max(dp[i + 1][j],dp[i][j - 1]);}ret = ret > dp[i][j] ? ret : dp[i][j];// 更新最值}}return ret;}
}

6.让字符串成为回⽂串的最⼩插⼊次数(hard)

链接:
https://leetcode.cn/problems/minimum-insertion-steps-to-make-a-string-palindrome/description/

分析:

在这里插入图片描述

代码:

class Solution {public int minInsertions(String s) {char[] ss = s.toCharArray();// 转化为字符数组int n = s.length();// 创建dp表int[][] dp = new int[n][n];for(int i = n - 1; i >= 0; i--) {for(int j = i; j < n; j++) {if(ss[i] == ss[j]) dp[i][j] = i + 1 < j ? dp[i + 1][j - 1] : 0;else dp[i][j] = Math.min(dp[i + 1][j],dp[i][j - 1]) + 1;}}return dp[0][n - 1];}
}

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

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

相关文章

Echarts地图之——如何给地图添加外边框轮廓

有时候我们希望给地图外围加一圈边框来增加美感 但实际情况中&#xff0c;我们需要把国界的边框和各个省份属于国界的边框相吻合&#xff0c;否则就会造成两者看起来是错位的感觉 这就需要我们把echarts registerMap的全国省份json和国界边框json的坐标相一致。 这个json我们可…

佳能机械制造将莅临2024第13届生物发酵产品与技术装备展

参展企业介绍 过滤与分离设备专业制造商 •碟式离心机及机组模块、系统 •卧式螺旋卸料沉降离心机及系统 江苏佳能机械制造有限公司位于中国“龙虾之都”——江苏盱眙&#xff0c;地处淮安西南部&#xff0c;淮河下游&#xff0c;洪泽湖南岸&#…

网络七层模型之表示层:理解网络通信的架构(六)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【LeetCode热题100】124.二叉树的最大路径和(二叉树)

一.题目要求 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点&#xff0c;且不一定经过根节点。 路径和 是路径中各节点值的总和。 给你一个二叉树的根节点 root …

Doris实践——叮咚买菜基于OLAP引擎的应用实践

目录 前言 一、业务需求 二、选型与对比 三、架构体系 四、应用实践 4.1 实时数据分析 4.2 B端业务查询取数 4.3 标签系统 4.4 BI看板 4.5 OLAP多维分析 五、优化经验 六、总结 原文大佬介绍的这篇Doris数仓建设实践有借鉴意义的&#xff0c;这些摘抄下来用作沉淀学…

docker-compose mysql

使用docker-compose 部署 MySQL&#xff08;所有版本通用&#xff09; 一、拉取MySQL镜像 我这里使用的是MySQL8.0.18&#xff0c;可以自行选择需要的版本。 docker pull mysql:8.0.18二、创建挂载目录 mkdir -p /data/mysql8/log mkdir -p /data/mysql8/data mkdir -p /dat…

软件测试基础理论、测试用例及设计方法、易混淆概念总结【软件测试】

一.软件测试基础理论 1.软件定义 软件是计算机系统中与硬件相互依存的一部分&#xff0c;包括程序、数据以及与其相关文档 的完整集合。 程序是按事先设计的功能和性能要求执行的指令序列&#xff1b; 数据是使程序能正常操作信息的数据结构&#xff1b; 文档是与程序开发、维…

对form表单对象中数组中的字段进行校验的方法

当对form表单中&#xff0c;数组readings中的字段进行校验时&#xff0c;prop和rules绑定要写成动态的&#xff0c;如下代码 <div v-for"(item,index) in form.readings"><el-form-item label"上次读数" > <!--prop"scds"-->…

LocalDateTime与时间戳转换

LocalDateTime与时间戳转换 1. 为什么LocalDateTime转时间戳需要时区2. 工具类 1. 为什么LocalDateTime转时间戳需要时区 讲道理&#xff0c;不管在什么时区&#xff0c;系统获取当前时间的时间戳都是一样的【因为时间戳指的是自 1970 年1月1日以来的秒数&#xff0c;所以无论…

使用ai智能写作场景之gpt整理资料,如何ai智能写作整理资料

Ai智能写作助手&#xff1a;Ai智能整理资料小助手 Ai智能整理资料小助手可试用3天&#xff01; 通俗的解释一下怎么用ChatGPT来进行资料整理&#xff1a; 搜寻并获取指定数量的特定领域文章&#xff1a; 想像你在和我说话一样&#xff0c;告诉我你想要多少篇关于某个话题的文…

在 Windows 11 上安装 MongoDB

MongoDB 是一个流行的 NoSQL 数据库&#xff0c;它提供了灵活的数据存储方案&#xff0c;而 MongoDB Compass 则是一个可视化管理工具&#xff0c;可以更轻松地与 MongoDB 数据库交互和管理。在本文中&#xff0c;我们将介绍如何在 Windows 11 上安装 MongoDB&#xff0c;并配置…

ESCTF-Web赛题WP

0x01-初次见面-怦然心动:your name? 随便输入一个字 根据提示可以看到 我们需要看源代码 直接 搜索 secret 关键字或者 ESCTF flag ESCTF{K1t0_iS_S0_HAPPy} 0x02-小k的请求 更安全的传参 post 参数为ESCTF 值为 love 自己的ip 同时还有个要求 是需要从度娘转过来 https://www…

QMT量化策略实盘(二)交易触发定时器run_time

上一篇分享中&#xff0c;介绍了QMT量化实盘中最常用的下单函数passorder&#xff0c;和它主要的参数。 如果再结合一个交易触发函数&#xff0c;就可以实现简单的量化交易策略了&#xff01;比如下面的代码可以实现&#xff1a; 在集合竞价期间以指定价买入中信证券100股 #c…

<el-table>设置一列为固定字段,其他列为循环生成

<el-table :data"tableData" style"width: 100%"><el-table-columnprop"name"label"固定字段名":formatter"formatter"></el-table-column><el-table-columnv-for"(item, index) in wordsColumns…

从小白-入门-进阶-高阶,四个阶段详细讲解单片机学习路线!

大家好&#xff0c;今天给大家介绍从小白-入门-进阶-高阶&#xff0c;四个阶段详细讲解单片机学习路线&#xff01;&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 单片机学习路…

简单线程池的实现

线程池的代码可以写的很复杂&#xff0c;这里就稍微简单一些 首先来看一下线程池的原则&#xff0c;下面的大框是服务器&#xff0c;而在服务器中维护一个任务队列。 然后在server中预先创建一批线程&#xff0c;这批线程和任务队列合在一起只用向外界提供一个入队列的接口。 …

cesium vue 绘制标记实体(撒点),监听鼠标左击事件

添加实体 const viewer new Cesium.Viewer(cesiumContainer, {})viewer.entities.add()查看实体 const viewer new Cesium.Viewer(cesiumContainer, {}) const billboard viewer.entities.add({...})viewer.zoomTo(billboard)删除实体 根据实体删除 if (billboard.value…

【热门话题】Yarn:新一代JavaScript包管理器的安装与使用

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 Yarn&#xff1a;新一代JavaScript包管理器的安装与使用引言一、Yarn的安装1. 系…

MFC(一)搭建空项目

安装MFC支持库 创建空白桌面程序 项目相关设置 复制以下代码 // mfc.h #pragma once #include <afxwin.h>class MyApp : public CWinApp { public:virtual BOOL InitInstance(); };class MyFrame : public CFrameWnd { public:MyFrame();// 消息映射机制DECLARE_…

基于springboot+vue+Mysql的财务管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…