今天是动态规划的最后一篇内容了,本篇主要是针对回文字符串这种“与众不同”的递推规律来进行讲解

647. 回文子串

        统计并返回这个字符串中 回文子串 的数目

暴力解法

        两层for循环,遍历区间起始位置和终止位置,然后还需要一层遍历判断这个区间是不是回文。所以时间复杂度:O(n^3)

动态规划

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

        如果大家做了很多这种子序列相关的题目,在定义dp数组的时候 很自然就会想题目求什么,我们就如何定义dp数组。

        绝大多数题目确实是这样,不过本题如果我们定义,dp[i] 为 下标i结尾的字符串有 dp[i]个回文串的话,我们会发现很难找到递归关系。dp[i] 和 dp[i-1] ,dp[i + 1] 看上去都没啥关系。所以我们要看回文串的性质。

        我们在判断字符串S是否是回文,那么如果我们知道 s[1],s[2],s[3] 这个子串是回文的,那么只需要比较 s[0]和s[4]这两个元素是否相同,如果相同的话,这个字符串s 就是回文串。那么此时我们是不是能找到一种递归关系,也就是判断一个子字符串(字符串下标范围[i,j])是否回文,依赖于,子字符串(下标范围[i + 1, j - 1])) 是否是回文

        所以为了明确这种递归关系,我们的dp数组是要定义成二维dp数组。dp[i][j](布尔类型):表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是dp[i][j]为true,否则为false。

  • 确定递推公式(这个地方要和遍历顺序一起理解,递推公式对于解题非常重要)

        在确定递推公式时,就要分析如下几种情况。整体上是两种,就是s[i]与s[j]相等,s[i]与s[j]不相等这两种。

        当s[i]与s[j]不相等,那没啥好说的了,dp[i][j]一定是false。

        当s[i]与s[j]相等时,这就复杂一些了,有如下三种情况

  1. 情况一:下标i 与 j相同,同一个字符例如a,当然是回文子串
  2. 情况二:下标i 与 j相差为1,例如aa,也是回文子串
  3. 情况三:下标:i 与 j相差大于1的时候,例如cabac,此时s[i]与s[j]已经相同了,我们看i到j区间是不是回文子串就看aba是不是回文就可以了,那么aba的区间就是 i+1 与 j-1区间,这个区间是不是回文就看dp[i + 1][j - 1]是否为true。
  • dp数组如何初始化  

        dp[i][j]初始化为false。

  • 确定遍历顺序

        遍历顺序可就有点讲究了。

        首先从递推公式中可以看出,情况三是根据dp[i + 1][j - 1]是否为true,在对dp[i][j]进行赋值true的。dp[i + 1][j - 1] 在 dp[i][j]的左下角所以一定要从下到上,从左到右遍历,这样保证dp[i + 1][j - 1]都是经过计算的

        总而言之,一个道理,都是为了保证dp[i + 1][j - 1]都是经过计算的。

  • 举例推导dp数组

        举例,输入:"aaa",dp[i][j]状态如下:

class Solution:def countSubstrings(self, s: str) -> int:dp = [[False] * len(s) for _ in range(len(s))]result = 0for i in range(len(s)-1, -1, -1): #注意遍历顺序for j in range(i, len(s)):if s[i] == s[j]:if j - i <= 1: #情况一 和 情况二result += 1dp[i][j] = Trueelif dp[i+1][j-1]: #情况三result += 1dp[i][j] = Truereturn result

双指针法

回文子串的对称中心有两种情况:

  • 奇数长度的回文子串(如 "aba"):中心是单个字符(示例中的 "b")。
  • 偶数长度的回文子串(如 "abba"):中心是两个相邻字符(示例中的 "bb")。

中心扩展法的逻辑是:

  • 枚举字符串中每个可能的中心(单个字符或相邻两个字符)。
  • 从中心向两侧扩展,判断扩展后的子串是否为回文。
  • 每扩展成功一次,就计数一个回文子串。
class Solution:def countSubstrings(self, s: str) -> int:result = 0for i in range(len(s)):result += self.extend(s, i, i, len(s)) #以i为中心result += self.extend(s, i, i+1, len(s)) #以i和i+1为中心return resultdef extend(self, s, i, j, n):res = 0while i >= 0 and j < n and s[i] == s[j]:i -= 1j += 1res += 1return res

516.最长回文子序列

        这种回文子序列可以删除元素是很难想的,因为规律不是很直观。本题和上题的区别在于:回文子串是要连续的,回文子序列可不是连续的! 

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

        dp[i][j]:字符串s在[i, j]范围内最长的回文子序列的长度为dp[i][j]

  • 确定递推公式

        在判断回文子串的题目中,关键逻辑就是看s[i]与s[j]是否相同。

        如果s[i]与s[j]相同,那么dp[i][j] = dp[i + 1][j - 1] + 2;

        如果s[i]与s[j]不相同,说明s[i]和s[j]的同时加入 并不能增加[i,j]区间回文子序列的长度,那么分别加入s[i]、s[j]看看哪一个可以组成最长的回文子序列。那么dp[i][j]一定是取最大的,即:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);

  • dp数组如何初始化

        当i与j相同,那么dp[i][j]一定是等于1的,即:一个字符的回文子序列长度就是1。其他情况dp[i][j]初始为0就行

  • 确定遍历顺序

        从递归公式中,可以看出,dp[i][j] 依赖于 dp[i + 1][j - 1] ,dp[i + 1][j] 和 dp[i][j - 1],所以遍历i的时候一定要从下到上遍历,这样才能保证下一行的数据是经过计算的

  • 遍历模拟

class Solution:def longestPalindromeSubseq(self, s: str) -> int:dp = [[0] * len(s) for _ in range(len(s))]for i in range(len(s)):dp[i][i] = 1for i in range(len(s)-1, -1, -1):for j in range(i+1, len(s)):if s[i] == s[j]:dp[i][j] = dp[i+1][j-1] + 2else:dp[i][j] = max(dp[i+1][j], dp[i][j-1])return dp[0][-1]

动态规划总结篇

代码随想录——动态规划总结篇

  • 动态规划基础(初步感受递推的关系)

  • 背包问题系列(递推二维到一维的理解)

  • 打家劫舍系列(线性递推顺序的延伸)

  • 股票系列(dp数组和数据输出的巧妙设置)*

  • 子序列系列(理解模拟遍历的重要性)

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

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

相关文章

Qt界面优化

1.QSS在网页前端开发领域中&#xff0c;CSS 是一个至关重要的部分&#xff0c;描述了一个网页的 “样式”&#xff0c;从而起到对网页美化的作用。所谓样式&#xff0c;包括不限于大小、位置、颜色、背景、间距、字体等等。网页开发作为 GUI 的典型代表&#xff0c;也对于其他客…

week1+2+3

408 计组 1.基本组成2.数据的表示和运算定点数&#xff1a;把数字分为定点整数和定点小数分开存储 浮点数&#xff1a;用科学计数法存储 原码 -全部取反-> 反码 反码 1->补码 补码 -符号位取反->移码带余除法&#xff1a;设x,m∈Z&#xff0c;m>0则存在唯一的整数q…

java8中javafx包缺少报错

今天拉取一个jdk1.8的项目里面有一个代码用到了javafx&#xff0c;这个我记得是jdk中的包&#xff0c;正常不应该报错的。然后发现jdk中还真没有&#xff0c;查了一下是因为版本问题。 Java 8 及之前&#xff1a;Oracle JDK 自带 JavaFX&#xff0c;OpenJDK 通常不包含Java 9 …

day072-代码检查工具-Sonar与maven私服-Nexus

文章目录0. 老男孩思想-选对池塘钓美人鱼1. 代码回滚方案2. SonarQube2.1 代码检查工具2.2 部署sonarqube2.2.1 软件要求2.2.2 安装软件2.2.3 启动sonar2.2.4 部署插件2.3 sonar检查java代码2.3.1 创建sona项目2.3.2 分析java代码2.3.3 Jenkins结合sonar检查代码2.4 sonar检查非…

【前端基础】15、列表元素、表格元素、表单元素(注:极其粗略的记载。)

一、列表元素 1、什么是列表元素2、有序列表&#xff08;ol、li&#xff09; ol有序列表 直接子元素只能是li。 li列表中的每一项。3、无序列表&#xff08;ul、li&#xff09; ol无序列表 直接子元素只能是li。 li列表中的每一项。4、定义列表&#xff08;dl、dt、dd&#xff…

IRFBG30PBF Vishay威世MOSFET场效应管

IRFBG30PBF Vishay威世&#xff1a;超快MOSFET 场效应管一、产品定位IRFBG30PBF 是Vishay威世推出的600V/30A N沟道功率MOSFET&#xff0c;采用第五代TrenchFET技术&#xff0c;专为开关电源、电机驱动、新能源逆变器等高功率场景设计。以85mΩ超低导通电阻和超快反向恢复&…

【07-AGI的讨论】

AI ANI&#xff1a;artificial narrow intelligence; 如 智能音箱&#xff1b;自动驾驶汽车&#xff0c;网络搜索&#xff0c;其他用于专业特定事项的工具&#xff1b; AGI&#xff1a;artificial general intelligence; building AI systems that could do anything a typical…

[激光原理与应用-225]:机械 - 3D图与2D图各自的作用

在机械设计与加工领域&#xff0c;3D图和2D图是两种核心的工程表达方式&#xff0c;它们在产品设计、制造、装配及维护等环节中扮演不同角色&#xff0c;具有互补性。以下是它们各自的作用及具体应用场景的详细解析&#xff1a;一、3D图的作用1. 直观展示产品全貌三维可视化&am…

【从零开始java学习|第一篇】java中的名词概念(JDK、JVM、JRE等等)

目录 一、核心运行环境三要素&#xff08;JVM/JRE/JDK&#xff09; 二、常用开发指令&#xff08;JDK 自带工具&#xff09; 三、一些其他概念 四、总结核心逻辑链 要入门 Java&#xff0c;理解核心概念之间的关系是基础。以下是 Java 中最核心的基础概念、工具及相关名词的…

UVa12345 Dynamic len(set(a[L:R]))

[TOC](UVa12345 Dynamic len(set(a[L:R]))) 题目链接 UVA - 12345 Dynamic len(set(a[L:R])) 题意 有编号从 0 到 n−1 的 n 个数&#xff0c;有两种操作&#xff1a; Q L R 询问编号 L 到编号 R−1 的数中有多少个不同的数字。M X Y 将编号为 X 的数字改为 Y。 你的任务就是…

[Ubuntu] VNC连接Linux云服务器 | 实现GNOME图形化

将桌面环境修改为 GNOME 并通过 VNC 远程访问的步骤 & TightVNC 的安装与配置说明&#xff1a;1. 安装 GNOME 桌面环境 sudo apt update sudo apt install ubuntu-gnome-desktop -y2. 安装 TightVNC 服务器 sudo apt install tightvncserver -y3. 初始化 VNC Server 并设置…

进程、网络通信方法

一、进程间通信(IPC)方法 适用于同一台主机上的进程间数据交换。 管道(Pipe) 匿名管道:单向通信,仅用于父子进程。 命名管道(FIFO):通过文件系统路径访问,支持无亲缘关系进程。 消息队列(Message Queue) 结构化消息(类型+数据),按类型读取,支持异步通信。…

[激光原理与应用-241]:设计 - 266n皮秒深紫外激光器,哪些因素影响激光器紫外光的输出功率?

一、短期稳定性266nm皮秒深紫外激光器紫外光输出功率的稳定性受非线性晶体性能、光学系统设计、热管理效果、重复频率与脉冲能量匹配度、环境干扰控制等因素影响&#xff0c;具体分析如下&#xff1a;1. 非线性晶体性能晶体选择与状态&#xff1a;BBO&#xff08;偏硼酸钡&…

Django配置sqllite之外的数据库

当连接到其他数据库后端时&#xff0c;如 MariaDB、MySQL、Oracle 或 PostgreSQL&#xff0c;将需要额外的连接参数。请参阅下面的 ENGINE 配置&#xff0c;了解如何指定其他数据库类型。这个例子是针对 PostgreSQL&#xff1a; 在django项目的settings.py文件里&#xff0c;关…

银河通用招人形机器人强化学习算法工程师了

人形强化学习算法工程师&#xff08;26届&#xff09;&#xff08;岗位信息已通过jobleap.cn授权&#xff0c;可在csdn发布&#xff09;银河通用机器人 北京收录时间&#xff1a; 2025年08月11日职位描述1. 研发基于深度强化学习的足式机器人运动控制算法&#xff0c;提升机器…

使用MongoDB存储和计算距离

一、MongoDB 计算距离的优势 优势说明原生地理空间索引支持 2dsphere 索引&#xff0c;高效处理地理坐标查询&#xff08;毫秒级响应&#xff09;。内置地理计算函数提供 $near、$geoWithin、$geoNear 等操作符&#xff0c;无需手动实现复杂计算。高性能基于B树索引优化&#…

鸿蒙开发-ArkUI中@Type作用详细解答

在鸿蒙&#xff08;HarmonyOS&#xff09;应用开发中&#xff0c;Type 是 ArkUI 框架中用于 类型定义和类型检查 的关键注解&#xff08;装饰器&#xff09;。它的主要作用是为自定义组件的属性提供明确的类型约束&#xff0c;确保数据传递的类型安全性。 核心作用解析&#xf…

MCU中的存储器映射(Memory Map)

MCU中的存储器映射(Memory Map) 在MCU(微控制器单元)中,存储器映射(Memory Map)是指将不同类型的存储器(如Flash、RAM、外设寄存器等)和功能模块分配到统一的地址空间的过程。这种映射方式使得CPU可以通过访问特定地址来读写数据或控制外设,而无需关心物理存储介质的…

Rust面试题及详细答案120道(11-18)-- 控制流与函数

《前后端面试题》专栏集合了前后端各个知识模块的面试题&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

数据结构-排序(2)

一、堆排序 &#xff08;借助树&#xff09;1.利用完全二叉树构建大顶堆 2.堆顶元素和堆底元素进行交换&#xff0c;堆底元素不再参与构建&#xff0c;剩余元素继续构建大顶堆3.时间复杂度 O(nlogn)1.完全二叉树&#xff1a;按照从上到下&#xff0c;从左到右的顺序进行排序2.…