代码随想录算法训练营第五十七天 | 回文

647. 回文子串

文档讲解:代码随想录 (programmercarl.com)

视频讲解:动态规划,字符串性质决定了DP数组的定义 | LeetCode:647.回文子串_哔哩哔哩_bilibili

状态:不会做。

思路

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

    本题如果我们定义,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。

  2. 确定递推公式

    整体上是两种,就是s[i]与s[j]相等,s[i]与s[j]不相等这两种。

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

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

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

    递归公式如下,

    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;}
    }
    

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

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

  3. dp数组如何初始化

    dp[i][j]可以初始化为true么? 当然不行,怎能刚开始就全都匹配上了。

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

  4. 确定遍历顺序

    首先从递推公式中可以看出,情况三是根据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[i][j]的定义,所以j一定是大于等于i的,那么在填充dp[i][j]的时候一定是只填充右上半部分

代码

class Solution {
public:int countSubstrings(string s) {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;}
};

516.最长回文子序列

文档讲解:代码随想录 (programmercarl.com)

视频讲解:动态规划再显神通,LeetCode:516.最长回文子序列_哔哩哔哩_bilibili

状态:不会做。

思路

回文子串是要连续的,回文子序列可不是连续的!

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

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

  2. 确定递推公式

    如果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]看看哪一个可以组成最长的回文子序列。

    加入s[j]的回文子序列长度为dp[i + 1][j]

    加入s[i]的回文子序列长度为dp[i][j - 1]

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

    在这里插入图片描述

    代码如下

    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]);
    }
    
  3. dp数组如何初始化

    首先要考虑当i 和j 相同的情况,从递推公式:dp[i][j] = dp[i + 1][j - 1] + 2; 可以看出 递推公式是计算不到 i 和j相同时候的情况。

    所以需要手动初始化一下,当i与j相同,那么dp[i][j]一定是等于1的,即:一个字符的回文子序列长度就是1。

    其他情况dp[i][j]初始为0就行,这样递推公式:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]); 中dp[i][j]才不会被初始值覆盖。

    vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));
    for (int i = 0; i < s.size(); i++) dp[i][i] = 1;
    
  4. 确定遍历顺序

    从递归公式中,可以看出,dp[i][j] 依赖于 dp[i + 1][j - 1]dp[i + 1][j]dp[i][j - 1],如图:

    在这里插入图片描述

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

    j的话,可以正常从左向右遍历。

    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]);}}
    }
    

代码

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];}
};

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

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

相关文章

驱动LSM6DS3TR-C实现高效运动检测与数据采集(3)----获取ID

概述 一旦传感器被正确初始化&#xff0c;可以通过SPI或I2C接口向传感器发送读取命令&#xff0c;并接收传感器返回的数据。这个读取过程包括获取LSM6DS3TR传感器提供的加速度计和陀螺仪数据&#xff0c;以及传感器对应的温度信息。 获取数据状态 STATUS_REG (1Eh)是该传感器…

chatgpt赋能python:Python中构造方法的介绍与应用

Python中构造方法的介绍与应用 在Python编程语言中&#xff0c;构造方法通常是类中的一个特殊方法&#xff0c;用于在对象创建时初始化其属性。构造方法使用__init__关键字来定义&#xff0c;而且通常会包含self参数&#xff0c;用于引用创建的新对象。在本文中&#xff0c;我…

木工专用计算机,木工做多功能电脑台带书柜架一体图片 自己打造电脑桌用实木还是生态木颗粒板...

黑色十字条纹状的书架&#xff0c;给人带来一种与众不同的感觉&#xff0c;褐色的实木地板铺贴在地面上&#xff0c;褐色的地面与整个橱柜形成了鲜明的对比。褐色给人一种灰溜溜的感觉&#xff0c;但是这种颜色很有古典美&#xff0c;而且褐色的地面又特别的耐脏&#xff0c;这…

python爬虫大众点评字体反爬

字形相同的字体反爬问题解析 问题所在&#xff1a;部分数据加载时使用网站自定义的字体&#xff0c;浏览器访问网页时字体文件会加载到浏览器中&#xff0c;爬虫访问时没有对应的自定义字体&#xff0c;所以就得不到那部分数据&#xff0c;如图1&#xff0c;加密的这部分数据在…

五笔字根语法口决

一、字根助记词 11G   王旁青头戋五一 12F   土士二干十寸雨 13D   大犬三&#xff08;羊&#xff09;古石厂 (“羊”指羊字底) 14S   木丁西 15A   工戈草头右框七   (“右框”即“匚”) 21H   目具上止卜虎皮   (“具”指具字的上部) 22J   日早…

字体反爬案例解析:大众点评

文章目录 字体反爬简介发送请求&#xff0c;获取网页源码提取字体信息&#xff0c;并将字体文件下载到本地建立基准字典引例提取需要字体反爬处理的信息提取不需要字体反爬的信息整理提取到的所有信息&#xff0c;并存入excel 字体反爬简介 什么是字体反爬&#xff1f; …

作文 我眼中的计算机1000字,我眼中的自己作文范文1000字(精选6篇)

我眼中的自己作文范文1000字(精选6篇) 在日常生活或是工作学习中&#xff0c;许多人都有过写作文的经历&#xff0c;对作文都不陌生吧&#xff0c;作文根据写作时限的不同可以分为限时作文和非限时作文。还是对作文一筹莫展吗&#xff1f;以下是小编为大家整理的我眼中的自己作…

基于深度学习的高精度家禽猪检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度家禽猪检测识别系统可用于日常生活中或野外来检测与定位家禽猪目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的家禽猪目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检…

智能管理PoE交换机

在这个万物互联的时代&#xff0c;数据与数据之间的相互传输交流&#xff0c;显得尤为重要。那么要怎样才能使计算机与传统的物联设备相连接呢&#xff1f;这时&#xff0c;串口服务器这一媒介的作用就凸显出来了。那么&#xff0c;你知道什么是串口服务器吗&#xff1f;串口服…

chatgpt赋能python:Python中构造函数的名称

Python中构造函数的名称 作为一名有10年Python编程经验的工程师&#xff0c;我深知Python语言中构造函数的重要性。在本文中&#xff0c;我将着重介绍Python中构造函数的名称&#xff0c;并阐述其在Python编程中的作用。 什么是构造函数&#xff1f; 构造函数是一种特殊类型…

C++ stack容器介绍

&#x1f914;stack容器介绍&#xff1a; &#x1f4d6; stack是一种数据结构&#xff0c;也可以被称为堆栈。它是一个容器&#xff0c;只允许在最顶层进行插入和删除&#xff0c;并且只能访问最后一个插入的元素。这个元素称为栈顶。所有新插入的元素都被放置在栈顶上面&#…

Mysql source命令报错

Mysql source命令报错 情况一&#xff1a;目录包含中文 放到没有中文的路径再执行 情况二&#xff1a;不小心加了分号 mysql会将分号当做文件名的一部分 固然报错 情况三&#xff1a;没有选择数据库 使用 use加数据库名 选择数据库后再执行 执行成功画面

Linux中的source命令

Linux中的source命令 1、source命令是什么&#xff1f; source命令也称为“点命令”&#xff0c;也就是一个点符号&#xff08;.&#xff09;&#xff0c;是bash的内部命令。 注意&#xff1a;该命令通常用命令“.”来替代 2、source命令 功能&#xff08;能干什么&#xff0…

qsort函数排序举例

使用qsort函数快速排序应用举例 这篇博客是用qsort函数来快速排列float型数据&#xff0c;分别按照年龄&#xff08;int型&#xff09;、姓名&#xff08;char型&#xff09;排列结构体。看懂就看懂&#xff0c;看不懂我也不想解释了。 简略解释一下qsort函数&#xff1a; v…

C语言qsort函数详解

目录 一、qsort函数的使用 二、qsort函数的模拟 一、qsort函数的使用 快排函数qsort是C的库函数&#xff0c;它可以对输入的任何类型的数组排序&#xff0c;通过该函数的函数声明我们可以看出它的使用方法&#xff1a; 举个栗子&#xff1a; #include<stdio.h> #inclu…

C语言 - qsort函数详解

文章目录 一.qsort函数简介1.qsort函数是C标准库<stdlib.h>库中的函数&#xff0c;使用时引入#include <stdlib.h>。**2.它的函数原型是 void qsort(void* base, size_t num, size_t width, int (*compare)(const void*, const void*))3.这些参数都是什么意思&…

qsort函数详解

上篇文章&#xff0c;笔者讲解了冒泡排序的方法&#xff0c;原文链接为&#xff1a;一个典列来带领大家了解冒泡排序思想_念君思宁的博客-CSDN博客&#xff0c;有意者请参考一下&#xff01; 最近笔者又浅学关于qsort函数的排序方法&#xff01;下面且听笔者一一道来&#xff…

C语言函数——qsort函数的使用

目录 一、qsort函数&#xff1a; 1、定义&#xff1a; 2、参数&#xff1a; &#xff08;1&#xff09;.基础 &#xff08;2&#xff09;.数字 &#xff08;3&#xff09;.大小 &#xff08;4&#xff09;.比较 二、总代码&#xff1a; 1、整型比较&#xff1a; 2、浮…

利用qsort函数快速排序

一.qsort函数的类型及参数 void qsort(void *base,size_t num,size_t width,int (*compare)(const void* elem1),const void* elem2)1.第一个参数base&#xff1a;待排序数组的首元素的地址&#xff0c;数据类型为void*。 2.第二个参数 num&#xff1a;待排序数组的元素个数&…

详解c语言中的qsort函数(有图)

目录 目录 一、qsort函数是什么 1、自定义冒泡函数时遇到的问题 2、qsort函数的作用 &#xff08;1&#xff09;int整形数组排序&#xff08;2&#xff09;浮点型数组排序&#xff08;3&#xff09;字符数组排序 &#xff08;4&#xff09;结构体排序 二、qsort函数…