力扣刷题day49|647回文子串、516最长回文子序列

news2025/1/12 10:43:30

文章目录

    • 647. 回文子串
      • 思路
        • 暴力解法
        • 动态规划五部曲
    • 516. 最长回文子序列
      • 思路
        • 动态规划五部曲

647. 回文子串

力扣题目链接

给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。

回文字符串 是正着读和倒过来读一样的字符串。

子字符串 是字符串中的由连续字符组成的一个序列。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

示例 1:

输入:s = "abc"
输出:3
解释:三个回文子串: "a", "b", "c"

示例 2:

输入:s = "aaa"
输出:6
解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"

思路

注意这道题要求的子串是要由连续的字符组成

暴力解法

两层for循环,一个遍历子串起始位置,一个遍历终止位置,找出所有可能的子串然后判断是不是回文的。

动态规划五部曲

  1. 确定dp数组以及下标的含义

dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是dp[i][j]为true,否则为false。

  1. 确定递推公式

分为两种情况讨论:

  • s[i]s[j]不相等

头尾两个字符不相等,那肯定的不是回文串,此时dp[i][j] = false

  • s[i]s[j]相等时
    • 情况一:下标ij相同,即同一个字符,例如a,必然是回文子串,此时dp[i][j] = true
    • 情况二:下标ij相差为1,即字符串由两个相同的字符组成,例如aa,必然是回文子串,此时dp[i][j] = true
    • 情况三:下标ij相差大于1的时候,例如cabac,此时s[i]s[j]已经相同了,再看aba是不是回文就可以了,那么aba的区间就是 i+1j-1区间,即判断dp[i + 1][j - 1]是否为true。
if (s.charAt(i) == s.charAt(j)) {
    if (j - i <= 1) {
        res++;
        dp[i][j] = true;
    }else if (dp[i + 1][j - 1] == true) {
        res++;
        dp[i][j] = true;
    }
}

result就是统计回文子串的数量。

注:这里我没有列出当s[i]与s[j]不相等的时候,因为在下面dp[i][j]初始化的时候,就初始为false。

  1. dp数组如何初始化

dp[i][j]刚开始是不知道是否回文的,所以dp[i][j]都初始化为false

  1. 确定遍历顺序

首先从递推公式中可以看出,情况三是根据**dp[i + 1][j - 1]**是否为true,再对dp[i][j]进行赋值的。

这两个式子的相对位置如下:

image-20221116145053067

发现dp[i + 1][j - 1] dp[i][j]的左下角

所以一定要从下到上从左到右遍历,这样保证dp[i + 1][j - 1]都是经过计算的。这样计算i的时候才能预先得到i+1的值。

// 记住从下往上,从左往右
for (int i = s.length() - 1; i >= 0; i--) {
    for (int j = i; j < s.length(); j++) {
  1. 举例推导dp数组

用示例二举例,输入:“aaa”,dp[i][j]状态如下:

image-20221116145631000

图中有6个true,所以就是有6个回文子串。

注:因为dp[i][j]的定义,所以j一定是大于等于i的,那么在填充dp[i][j]的时候一定是只填充右上半部分。

完整代码:

public int countSubstrings(String s) {
    boolean[][] dp = new boolean[s.length()][s.length()];
    int res = 0; // 记录回文子串总数

    // 记住从下往上,从左往右
    for (int i = s.length() - 1; i >= 0; i--) {
        for (int j = i; j < s.length(); j++) {
            if (s.charAt(i) == s.charAt(j)) {
                if (j - i <= 1) {
                    res++;
                    dp[i][j] = true;
                }else if (dp[i + 1][j - 1] == true) {
                    res++;
                    dp[i][j] = true;
                }
            }
        }
    }

    return res;
}

516. 最长回文子序列

力扣题目链接

给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

示例 1:

输入:s = "bbbab"
输出:4
解释:一个可能的最长回文子序列为 "bbbb" 。

示例 2:

输入:s = "cbbd"
输出:2
解释:一个可能的最长回文子序列为 "bb" 。

思路

注意这里的子序列只用满足相对顺序,不用连续

动态规划五部曲

  1. 确定dp数组以及下标的含义

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

  1. 确定递推公式

和上一题一样,同样是两个情况

  • 如果s[i]s[j]不相同,说明s[i]s[j]同时加入并不能增加[i,j]区间回文子串的长度,那我们就考虑是留下果s[i]还是s[j]继续找回文子串

    • 留下s[i],去掉s[j]找回文子序列,此时dp[i][j] = dp[i][j - 1]

      image-20221116154029731

    • 留下s[j],去掉s[i]找回文子序列,此时dp[i][j] = dp[i + 1][j]

      image-20221116153912796

那么dp[i][j]一定是取最大的,即:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])

  • 如果s[i]s[j]相同

    • 如果i == j,即字符串长度为1,一定是回文子串,dp[i][j] = 1
    • 如果j - i == 1,即字符串由两个相同的字符组成,一定是回文子串,dp[i][j] = 2
    • 如果j - i >1,这时候我们要看里面子串的最长回文子序列长度,如果里面也是回文,那么就最后要加上s[i]s[j]这两个字符,如下图,所以dp[i][j] = dp[i+1][j-1] + 2
if (s.charAt(i) == s.charAt(j)) {
    if (j - i <= 1) { // 情况一二
        dp[i][j] = j - i + 1;
    }else { // 情况三
        dp[i][j] = dp[i + 1][j - 1] + 2;
    }
} else { // s[i]和s[j]不等
    dp[i][j] = Math.max(dp[i][j - 1], dp[i + 1][j]);
}
  1. dp数组如何初始化

一开始不知道范围内存不存在回文子序列,所以全部初始化为0

  1. 从递推公式dp[i][j] = dp[i + 1][j - 1] + 2dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]) 可以看出,dp[i][j]是依赖于dp[i + 1][j - 1]dp[i + 1][j]

image-20221116155244671

所以遍历i的时候一定要从下到上从左到右遍历,这样才能保证,下一行的数据是经过计算的。

for (int i = s.length() - 1; i >= 0; i--) {
    for (int j = i; j < s.length(); j++) {
  1. 举例推导dp数组

以示例二为例,输入s:“cbbd” 为例,dp数组状态如图:

image-20221116155613988

完整代码:

public int longestPalindromeSubseq(String s) {
    int[][] dp = new int[s.length()][s.length()];

    for (int i = s.length() - 1; i >= 0; i--) {
        for (int j = i; j < s.length(); j++) {
            if (s.charAt(i) == s.charAt(j)) {
                if (j - i <= 1) { // 情况一二
                    dp[i][j] = j - i + 1;
                }else { // 情况三
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                }
            } else { // s[i]和s[j]不等
                dp[i][j] = Math.max(dp[i][j - 1], dp[i + 1][j]);
            }
        }
    }

    return dp[0][s.length() - 1];
}

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

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

相关文章

代码随想录算法训练营第一天|LeetCode704二分查找、LeetCode27移除元素

LeetCode704二分查找 题目链接&#xff1a;704二分查找 思路&#xff1a; 以前刷过不少题&#xff0c;也看过不少题解&#xff0c;就记得区间有不少原则&#xff0c;乍一想有哪些想不起来了&#xff0c;反正我是选择了最简单易懂的左闭右闭原则。 1、区间左闭右闭原则。 2、w…

SpringBoot SpringBoot 开发实用篇 2 配置高级 2.3 常用计量单位应用

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 开发实用篇 文章目录SpringBootSpringBoot 开发实用篇2 配置高级2.3 常用计量单位应用2.3.1 问题引入2.3.2 常用计量单位应…

实验2 存储器设计与实现【计算机组成原理】

实验2 存储器设计与实现【计算机组成原理】实验2 存储器设计与实现一、实验目的二、实验环境三、实验原理四、实验任务五、实验结果&#xff1a;六、心得体会&#xff1a;实验2 存储器设计与实现 一、实验目的 掌握单端口RAM和ROM原理和设计方法。掌握32位数据的读出和写入方…

【LeetCode-中等】343. 整数拆分(详解)

题目 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 力扣&#xff1a;题目链接 方法1&#xff1a;动态规划 完全不了解动态规划&#xff1f; 动态规划…

图像运算和图像增强九

图像运算和图像增强九 图像锐化之 Roberts、Prewitt 算子实现边缘检测 &#xff08;1&#xff09;图像锐化 图像锐化的目的是为了使图像的边缘、轮廓线以及图像的细节变得清晰&#xff0c;经过平滑的图像变得模糊的根本原因是图像受到了平均或积分运算&#xff0c;因此可以对…

LeetCode刷题(python版)——Topic70. 爬楼梯

一、题设 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法可以爬到楼顶。 1. 1 阶 1 阶 2. 2 阶 示例…

Flutter混编之路IOS插件0基础开发(mac环境)

本文默认你安装了Android Studio、Xcode具备flutter开发环境&#xff0c;并且会dart语言的基础使用&#xff0c;Android、ios原生开发不会也没啥关系&#xff0c;就是会很费劲啦。 1.创建插件 在Android studio 点击File-->new Flutter Project-->Flutter 取好名字&…

Web大学生网页作业成品:基于html制作中国科技发展网站设计题材【航天之路7页】HTML+CSS+JavaScript

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Celery快速使用(定时任务、Django中使用Celery、秒杀逻辑、双写一致性)

文章标题一、Celery快速使用二、Celery包结构三、Celery异步任务 延时任务 定时任务四、Django中使用Celery五、秒杀逻辑六、双写一致性1&#xff09;路飞项目接口加缓存2&#xff09;Celery定时任务实现双写一致性一、Celery快速使用 简单介绍Celery Celery官网:http://www.…

busybox的实现原理分析(C语言实现简易版的busybox)

1、linux中实现命令的两种方式 1.1、命令都是单独的可执行程序 aston:~$ ls -l /bin/ls -rwxr-xr-x 1 root root 138208 2鏈 8 2022 /bin/ls aston:~$ aston:~$ ls -l /bin/mkdir -rwxr-xr-x 1 root root 68096 2鏈 8 2022 /bin/mkdir aston:~$ aston:~$ file /bin/ls…

元数据性能大比拼:HDFS vs S3 vs JuiceFS

元数据是存储系统的核心大脑&#xff0c;元数据性能对整个大数据平台的性能和扩展能力至关重要。尤其在处理海量文件的时候。在平台任务创建、运行和结束提交阶段&#xff0c;会存在大量的元数据 create&#xff0c;open&#xff0c;rename 和 delete 操作。因此&#xff0c;在…

Sass 使用说明

CSS 样式表越来越大、 越来越复杂、越来越难以维护。这就是预处理可以提供帮助的地方。 Sass 为你提供了 CSS 中还不存在的特性&#xff0c;例如变量、 嵌套、混合、继承和其它实用的功能&#xff0c;让编写 CSS 代码变得有意思。 最直接的方式就是在命令行中调用 sass 命令。安…

java和vue的狱警管理系统监狱系统狱务管理系统

简介 狱警管理系统监狱系统狱务管理系统&#xff0c;主要是管理罪犯教育改造、劳动改造、案件管理&#xff0c;罪犯信息管理等 演示视频 https://www.bilibili.com/video/BV1VG411P7YL/?zw&vd_sourcefa4ffd66538a5ca679a754398a6fdb5f 技术&#xff1a;springbootvueel…

git的下载与安装

1. 下载地址 根据自己的电脑配置信息&#xff0c;选用合适的版本进行下载即可&#xff0c;我的电脑上64位win11&#xff0c;所以我选择了64位的widnows版本&#xff0c;下面其他内容也以此版本展开。 windows&#xff1a;Git - Downloading Package macOS&#xff1a;Git - …

Linux-进程管理

基本介绍 在Linux中&#xff0c;每个执行的程序都称为一个进程&#xff0c;每一个进程都分配一个ID号&#xff08;pid) 程序运行起来就产生了进程 ps ps命令用来查看在目前系统中&#xff0c;有哪些正在执行的进程&#xff0c;以及他们执行的状况&#xff0c;可以不加任何参…

K_A05_004 基于 STM32等单片机驱动2X2块(8X8)点阵模块(MAX7219)显示0-9与中文

目录 一、资源说明 二、基本参数 1、参数 2、引脚说明 三、通信协议说明 工作时序 对应程序: 四、部分代码说明 1、接线说明 1.1、STC89C52RC2X2块(8X8)点阵模块&#xff08;MAX7219&#xff09; 1.2、STM32F103C8T62X2块(8X8)点阵模块&#xff08;MAX7219&#xff09; 2、亮…

年产10000吨餐厨垃圾制备氨基酸有机肥工厂设计

目录 摘 要 I Abstract II 第1章 餐厨垃圾概况 1 1.1餐厨垃圾性质 1 1.2餐厨垃圾无害化处理的必要性 1 1.3餐厨垃圾资源化处理工艺 1 1.3.1加工有机肥 2 1.3.2好氧堆肥 3 1.3.3厌氧消化 3 第2章 项目概述 4 2.1氨基酸有机肥的介绍 4 2…2 氨基酸有机肥的性质 4 2.3 氨基酸有机肥…

重温Python基础,都是最基础的知识点

前言 最近有很多朋友刚接触python学的还是有点模糊 还有的朋友就是想重温一下基础内容&#xff0c;毕竟基础不牢地动山摇 行吧&#xff0c;就总结了以下的一些知识点&#xff0c;可以都看看哈 一、开发环境搭建 更多学习资料.点击领取即可 1.1 Python解释器的安装 Python解…

三个最常见OSPF故障的实操检测步骤

大家好&#xff0c;我是小咖老师。 OSPF排错咱们已经讲过几期了&#xff0c;有同学反馈说看不懂&#xff0c;内容太多也不好记&#xff0c;今天咱就挑最常见的三个&#xff0c;给大家分析讲解一下。 1、OSPF邻居建立不成功 2、OSPF不能发现其他区域的路由 3、CPU过高问题 O…

-1- threejs 场景常见的方法和属性

场景常见的方法和属性场景的作用场景的坐标系常用的属性常用的方法场景的作用 场景(THREE.Scene)用于存储物体、光源、摄像机及其渲染所需要的其他的对象集合。THREE.Scene 对象又是被称为场景图&#xff0c;它不仅仅是一个对象数组&#xff0c;还包含了整个场景图树形结构中的…