代码随想录刷题day57|回文子串最长的回文子序列

文章目录

  • day57学习内容
  • 一、回文子串
    • 1.1、动态规划五部曲
      • 1.1.1、 确定dp数组(dp table)以及下标的含义
      • 1.1.2、确定递推公式
      • 1.1.3、 dp数组如何初始化
      • 1.1.4、确定遍历顺序
      • 1.1.5、输出结果
    • 1.2、代码
  • 二、最长的回文子串
    • 2.1、动态规划五部曲
      • 2.1.1、 确定dp数组(dp table)以及下标的含义
      • 2.1.2、确定递推公式
      • 2.1.3、 dp数组如何初始化
      • 2.1.4、确定遍历顺序
      • 2.1.5、输出结果
    • 2.2、代码
      • 2.2.1、如何理解dp[i][j] = dp[i + 1][j - 1] + 2;
  • 总结
    • 1.感想
    • 2.思维导图


day57学习内容

day57主要内容

  • 2个字符串的删除操作
  • 最长的回文子串

声明
本文思路和文字,引用自《代码随想录》


一、回文子串

647.原题链接

1.1、动态规划五部曲

1.1.1、 确定dp数组(dp table)以及下标的含义

  • dp[i][j]是一个布尔值,用于表示子字符串s[i...j]是否为回文。如果dp[i][j]true,则说明从索引ij的子字符串是回文。

1.1.2、确定递推公式

  • 基本情况
    • i == j时,s[i...j]是单个字符,显然是回文。
    • j == i + 1时,如果s[i] == s[j],则s[i...j]是由两个相同字符组成的回文。
  • 递推关系
    • 对于j > i + 1,如果s[i] == s[j]dp[i+1][j-1]true(即去除两端字符后的子字符串是回文),则s[i...j]也是回文。

或者这么理解
在每次循环中,会判断当前子字符串s[i...j]是否是回文:

  • 基本条件 (if (chars[i] == chars[j])): 如果两端的字符相同,进一步判断是否构成回文。
    • 情况一和情况二 (if (j - i <= 1)): 如果ij相同或者是相邻的位置(即子字符串长度为1或2),则这个子字符串是回文。
    • 情况三 (else if (dp[i + 1][j - 1])): 如果不是上述情况,但内部的子字符串s[i+1...j-1]是回文(由dp[i+1][j-1]true表示),那么s[i...j]也是回文。

在每个条件成立时,都会将dp[i][j]设置为true并将结果计数器result加一。

1.1.3、 dp数组如何初始化

  • 初始状态:由于所有的布尔值在Java中默认初始化为falsedp数组最开始全部为false。在遍历过程中,我们会根据回文的条件来更新特定的dp[i][j]true

1.1.4、确定遍历顺序

  • 外层循环从字符串的末尾开始向前遍历(即ilen-1降至0)。这样做确保当我们检查dp[i][j]是否为回文时,dp[i+1][j-1](即内部子字符串)的值已经被确定。
  • 内层循环i开始向字符串的末尾遍历(即ji增至len-1)。这种方式可以确保每次检查的都是从位置i开始的所有可能的子字符串。

1.1.5、输出结果

  • 结果result是一个整数,用于计数整个字符串中所有的回文子串。每次当找到一个回文(即dp[i][j]被设置为true)时,result就增加1。最终,方法返回result值,这就是字符串s中所有回文子串的数量。

1.2、代码

class Solution {public int countSubstrings(String s) {// 将输入字符串转换为字符数组,便于单个字符访问char[] chars = s.toCharArray();// 获取字符串的长度int len = chars.length;// 初始化一个二维布尔数组来存储回文状态,dp[i][j]为true表示s[i...j]是回文boolean[][] dp = new boolean[len][len];// 用于计数回文子串的数量int result = 0;// 外层循环:从字符串的末尾开始向前遍历for (int i = len - 1; i >= 0; i--) {// 内层循环:从当前字符位置向字符串的末尾遍历for (int j = i; j < len; j++) {// 检查两端的字符是否相同if (chars[i] == chars[j]) {// 检查是否是最基本的回文条件:单个字符或两个相同的字符if (j - i <= 1) {// 如果是,标记为回文并计数dp[i][j] = true;result++;} else if (dp[i + 1][j - 1]) { // 检查内部子字符串是否是回文// 如果内部子字符串也是回文,那么整个字符串也是回文dp[i][j] = true;result++;}}}}// 返回回文子串的总数return result;}
}

二、最长的回文子串

516.原题链接

2.1、动态规划五部曲

2.1.1、 确定dp数组(dp table)以及下标的含义

  • dp[i][j]表示字符串中从索引i到索引j的子字符串的最长回文子序列的长度。

2.1.2、确定递推公式

  • 字符相等的情况
    s[i]等于s[j]时,意味着我们可以在子字符串s[i+1...j-1]的最长回文子序列的两端分别添加s[i]s[j]。因为两端字符相等且已经构成了s[i+1...j-1]的回文子序列的两端,这会形成一个新的更长的回文子序列。这就是为什么递推公式是dp[i][j] = dp[i+1][j-1] + 2

  • 字符不等的情况
    s[i]不等于s[j]时,意味着s[i]s[j]不能同时被用来形成一个更长的回文子序列。在这种情况下,我们有两个选择:

    1. 忽略字符s[i],考虑子字符串s[i+1...j]
    2. 忽略字符s[j],考虑子字符串s[i...j-1]
      因此,我们需要比较这两个子问题的解,选取其中较大的一个,递推公式为dp[i][j] = max(dp[i+1][j], dp[i][j-1])

递推公式的实现

  • 在初始化时,每个单字符子字符串自身是一个长度为1的回文子序列,所以dp[i][i] = 1
  • 对于每一对ij(其中i <= j),根据上述规则更新dp[i][j]

示例
考虑字符串“cbbd”:

  • 如果i=0j=3,且s[0] != s[3],则考虑dp[1][3]dp[0][2],取最大值。

没有废话的版本

  • 当字符相等时:如果s[i]s[j]相等,这意味着我们可以在内部子字符串s[i+1...j-1]的最长回文子序列的基础上加上这两个相等的字符,形成更长的回文子序列。因此,递推公式是dp[i][j] = dp[i+1][j-1] + 2
  • 当字符不相等时:如果s[i]s[j]不相等,那么最长的回文子序列要么不包含s[i],要么不包含s[j]。因此,递推公式是dp[i][j] = max(dp[i+1][j], dp[i][j-1])

2.1.3、 dp数组如何初始化

  • 数组定义:定义了一个二维数组dp,其维度为len+1 x len+1,其中len是输入字符串s的长度。这个数组用来存储所有子字符串的最长回文子序列的长度。
  • 基本回文:每个单字符都是一个回文子序列,所以在遍历开始前,将对角线上的dp[i][i]初始化为1,即dp[i][i] = 1。这表示每个由单个字符组成的子字符串都至少有一个字符的回文子序列。

2.1.4、确定遍历顺序

  • 外层循环i从字符串的最后一个字符开始,递减到第一个字符。这种从后向前的遍历方式是为了保证当处理dp[i][j]时,dp[i+1][j-1]已经被计算,符合动态规划的依赖顺序。
  • 内层循环ji+1开始,递增到字符串的末尾。这样可以确保我们总是在处理长度大于1的子字符串,并且当i固定时,我们从较短的子字符串逐渐处理到较长的子字符串。

2.1.5、输出结果

  • 输出结果:整个字符串的最长回文子序列长度存储在dp[0][len-1]中,其中len是字符串s的总长度。这个值在所有计算完成后直接返回,即为所求的整个字符串的最长回文子序列的长度。

2.2、代码

public class Solution {public int longestPalindromeSubseq(String s) {// 获取输入字符串的长度int len = s.length();// 创建一个二维数组dp,用于存储子字符串的最长回文子序列长度int[][] dp = new int[len][len];// 从字符串的最后一个字符开始,反向遍历,确保计算dp[i][j]时dp[i+1][j-1]已经被计算过for (int i = len - 1; i >= 0; i--) {// 单个字符总是回文子序列,长度为1dp[i][i] = 1;// 从i+1开始向右遍历,计算所有可能的子字符串for (int j = i + 1; j < len; j++) {// 如果两端的字符相同,可以在dp[i+1][j-1]的基础上两端各加一个字符if (s.charAt(i) == s.charAt(j)) {dp[i][j] = dp[i + 1][j - 1] + 2;} else {// 如果两端字符不同,取不包含当前字符i或字符j的子字符串的最长回文子序列的最大值dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);}}}// dp[0][len-1]存储了整个字符串的最长回文子序列长度return dp[0][len - 1];}
}

2.2.1、如何理解dp[i][j] = dp[i + 1][j - 1] + 2;

当我们查看字符串的一个子序列,假设它的起始索引是 i,结束索引是 j,我们需要决定s[i...j]的最长回文子序列是什么。在递推公式dp[i][j] = dp[i+1][j-1] + 2;中:

  • dp[i+1][j-1]: 这部分代表子字符串s[i+1...j-1]的最长回文子序列的长度。即当我们去掉当前考虑的子字符串两端的字符后,内部子字符串的最长回文子序列长度。

  • 加2的逻辑:如果s[i]s[j]字符相同,这意味着我们可以在s[i+1...j-1]的最长回文子序列的基础上,在两端各加上字符s[i]s[j],从而形成一个更长的回文子序列。因此,整个子字符串s[i...j]的最长回文子序列长度会是内部子字符串s[i+1...j-1]的长度加2(加上两端相同的字符)。

举个例子

假设有字符串 “cbbd”,我们想知道子字符串 “bb” 的最长回文子序列。

  1. 初始化

    • dp[i][i] 对于所有 i 都设为 1,因为每个单独的字符都是长度为1的回文子序列。
  2. 填充动态规划表

    • 当我们检查 “bb”(即 i=1, j=2)时,因为两端的字符相同(s[1]s[2] 都是 ‘b’)。
    • 查看去掉两端的子字符串 “b[1+1…2-1]”,即 dp[2][1],但这是无效的区间,其基本长度为0(在实际初始化中可能直接被视为基础情况)。
    • 由于两端字符相同,我们可以在这个基础上前后各添加一个 ‘b’,因此,dp[1][2] 的值应更新为 0 + 2 = 2

总结

1.感想

  • 动态规划了终于结束了。。

2.思维导图

本文思路引用自代码随想录,感谢代码随想录作者。

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

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

相关文章

JVM 方法调用之方法分派

JVM 方法调用之方法分派 文章目录 JVM 方法调用之方法分派1.何为分派2.静态分派3.动态分派4.单分派与多分派5.动态分派的实现 1.何为分派 在上一篇文章《方法调用之解析调用》中讲到了解析调用&#xff0c;而解析调用是一个静态过程&#xff0c;在类加载的解析阶段就确定了方法…

ECharts:五大卓越在线示例库助力高效数据可视化开发

1. ECharts官方示例库 ECharts官网提供的示例库是最权威、最新的展示平台&#xff0c;涵盖了所有基础和高级图表类型&#xff0c;每个示例都配有详尽的代码解释和配置说明。开发者可以直接查看源代码&#xff0c;复制粘贴后稍加修改就能应用于实际项目中。 2. Make A Pie - EC…

生成对抗网络 – Generative Adversarial Networks | GAN

目录 生成对抗网络 GAN 的基本原理 非大白话版本 第一阶段:固定「判别器D」,训练「生成器G」

【笔试训练】day4

不到5分钟写完&#xff0c;今天的题又又又难一点啦! 1.Fibonacci数列 思路&#xff1a; 直接模拟一遍斐波那契数列的递增过程&#xff0c;大于n就直接结束。因为后面只会越来越大&#xff0c;跟题目求的最小步数不符。在这个过程中用一个变量去维护这个当前的元素与目标n还差…

【编程TOOL】VC++6.0下载安装配置使用保姆式教程

目录 ​编辑 1.软件介绍 2.软件下载 3.软件安装 3.1.下载得到可执行文件并双击进行安装 3.2. 点击下一步 3.3. 选择安装位置 3.4. 勾选“创建桌面快捷方式”并点击下一步 5. 点击安装并等待 3.6. 先取消运行&#xff0c;后点击完成&#xff0c;软件即安装完毕 4.兼容性配置 4.1…

基于SpringBoot+Vue的疾病防控系统设计与实现(源码+文档+包运行)

一.系统概述 在如今社会上&#xff0c;关于信息上面的处理&#xff0c;没有任何一个企业或者个人会忽视&#xff0c;如何让信息急速传递&#xff0c;并且归档储存查询&#xff0c;采用之前的纸张记录模式已经不符合当前使用要求了。所以&#xff0c;对疾病防控信息管理的提升&a…

IoC与Spring

目录 IoC控制反转 现实案例 特点 目的 DI依赖注入 小总结 介绍Spring 狭义和广义上的Spring 传统编码方式的不足 需求引入 弊端分析 IoC控制反转 现实案例 1、买水果问老板各种水果的口感而不是自己去挨个尝试一遍。 2、买房子找中介而不是自己去花时间找房东。…

别找了,这35份Excel自动排班表真的好用!

别再自己做排班表了&#xff0c;调了半天不好看格式还不对。 看看自己需要的是哪些类型的排班表&#xff1f;是公司值班&#xff0c;还是直播排班&#xff0c;还是考勤汇总&#xff0c;总有一个适合你。 刚整理的35份办公常用的排班表&#xff0c;希望能帮到你&#xff01; …

Spring VS Spring Boot

目录 定义 Spring Spring Boot 区别 优劣对比 Spring Spring的优势 Spring的劣势 Spring Boot Spring Boot的优势 Spring Boot的劣势 适用场景 Spring的适用场景 Spring Boot的适用场景 初学者如何选择学习 定义 Spring Spring是一个轻量级的、开源的Java开发…

Redis魔法:解锁高性能缓存的神奇之门(二)

本系列文章简介&#xff1a; 在现代的软件开发中&#xff0c;高性能和高可用性是每个开发者都追求的目标。然而&#xff0c;随着数据量和访问频率的不断增长&#xff0c;传统的数据库存储方案往往难以应对这种挑战。这就引出了一个问题&#xff1a;如何在保证数据的高效访问和持…

基于Python的机器学习的文本分类系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

CentOS 7安装Redis

说明&#xff1a;本文介绍如何在CentOS 7操作系统下安装Redis 下载安装 首先&#xff0c;去官网上下载所需要安装的版本&#xff0c;官网地址&#xff1a;https://download.redis.io/releases/&#xff0c;我这里下载3.2.1版本的 下载完&#xff0c;上传到云服务器上&#xf…

<router-link>出现Error: No match for {“name“:“home“,“params“:{}}

在将<a></a>标签换到<router-link></router-link>的时候出现No match for {"name":"home","params":{}}这样的错误&#xff0c;其中格式并无错误&#xff0c; <router-link class"navbar-brand active" …

她在《繁花》大放异彩,“浪姐”暴瘦15斤,打脸了不看好她的观众

不知不觉&#xff0c;《浪姐》已经迎来第5季了。播到第4季的时候&#xff0c;改名成《乘风破浪2023》&#xff0c;这一季叫《乘风2024》&#xff0c;和前几季相比&#xff0c;热度依然不减。 都说3个女人一台戏&#xff0c;更何况这个节目&#xff0c;每次能请到30位姐姐&…

刷题。。。。。。

1.ezmd5 根据题目提示 我们知道应该是要上传两张md5值相同的图片 根据原文链接&#xff1a;cryptanalysis - Are there two known strings which have the same MD5 hash value? - Cryptography Stack Exchange 把保存下来的图片上传一下 得到flag 2.ezhttp 根据原文链接&…

【python】初识爬虫

Python爬虫介绍 目录 一、概述二、Python爬虫的基本构成爬虫引擎解析器数据存储三、Python爬虫的主要技术请求与响应URL管理页面解析数据存储四、Python爬虫的应用场景数据采集搜索引擎竞品分析价格监控五、Python爬虫的开发流程六、常用的库

Rockchip Android13 Vold(三):App层

目录 前言 一:处理Volumes 1、接收StorageVolume 2、创建MediaVolume 3、附加MediaVolume

FewShotPromptTemplate和SemanticSimilarityExampleSelector的学习

FewShotPromptTemplate 和 SemanticSimilarityExampleSelector 是在少样本学习&#xff08;FewShot Learning&#xff09;场景中常用的两种技术&#xff0c;它们在提高模型泛化能力和减少对大量标注数据的依赖方面扮演着重要角色。 下面我会解释它们之间的关系&#xff1a; F…

node基础 第二篇

01 ffmpeg开源跨平台多媒体处理工具&#xff0c;处理音视频&#xff0c;剪辑&#xff0c;合并&#xff0c;转码等 FFmpeg 的主要功能和特性:1.格式转换:FFmpeg 可以将一个媒体文件从一种格式转换为另一种格式&#xff0c;支持几乎所有常见的音频和视频格式&#xff0c;包括 MP…

冲上热搜-奇安信今年的年终奖。。

最近,奇安信宣布全员无年终奖&#xff0c;同时冲上了脉脉热搜榜第一。作为网安界的一哥&#xff0c;奇安信的决定无疑给许多期待年终奖的员工带来了沉重的打击。 从公司内部的绩效考核机制来看,奇安信将员工分为了5个档次:S、A、B、B、B-。而大多数员工被评定为中等的B档,这意味…