Day56|动态规划part16:647. 回文子串、516. 最长回文子序列、动态规划总结篇

news2025/1/11 21:06:04

647. 回文子串

leetcode链接:力扣题目链接

视频链接:动态规划,字符串性质决定了DP数组的定义 | LeetCode:647.回文子串

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

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

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

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

示例 1:

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

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

动态规划解法

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

首先看到题目说是一个字符串,本来考虑dp一维数组,不过本题如果我们定义,dp[i] 为 下标i结尾的字符串有 dp[i]个回文串的话,我们会发现很难找到递归关系。

dp[i] 和 dp[i-1] ,dp[i + 1] 看上去都没啥关系。

image

所以应该定义的还是二维数组,布尔类型的dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是dp[i][j]为true,否则为false。

  1. 确定递推公式

如果s[i] 不等于s[j],没啥好说的,dp[i][j] = false

如果s[i] == s[j],比较下一位,dp[i][j] = dp[i + 1][ j - 1]。这是错的!!!只考虑了一种情况,其实有三种情况。

有如下三种情况

  • 情况一:下标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。
  1. dp数组的初始化

全都初始化为false。

  1. 确定遍历顺序

i从前往后,j从后往前(这是错的 !!!因为dp[i][j]需要用到dp[i+1][j - 1],

因为dp[i+1]必须在dp[i]前得出结果;

image

所以一定要从下到上,从左到右遍历,这样保证dp[i + 1][j - 1]都是经过计算的

也就是i从后往前, j从前往后

这里需要注意的是,不是说i是前面匹配j从后往前匹配吗?这里dp数组的遍历顺序并不一定是指字符串实际上的遍历顺序,而是dp数组填充的顺序。

  1. 打印dp数组

image

最终代码:

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;
    }
};
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(n^2)

这里注意我们找的是最终回文串的长度,dp数组是bool,只用来记录状态,因此需要一个result来记录长度。注意因为dp[i][j]的定义,所以j一定是大于等于i的,那么在填充dp[i][j]的时候一定是只填充右上半部分。

双指针解法

这里直接放卡哥的代码了,二刷再来琢磨琢磨:

class Solution {
public:
    int countSubstrings(string s) {
        int result = 0;
        for (int i = 0; i < s.size(); i++) {
            result += extend(s, i, i, s.size()); // 以i为中心
            result += extend(s, i, i + 1, s.size()); // 以i和i+1为中心
        }
        return result;
    }
    int extend(const string& s, int i, int j, int n) {
        int res = 0;
        while (i >= 0 && j < n && s[i] == s[j]) {
            i--;
            j++;
            res++;
        }
        return res;
    }
};
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)

516. 最长回文子序列

leetcode链接:力扣题目链接

视频链接:动态规划再显神通,LeetCode:516.最长回文子序列

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

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

示例 1:

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

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

注意这题求的是子序列,不是子串,子序列可能是不连续的。

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

仿照上题,dp[i][j] 表示闭区间[i,j]组成的子串的最长的长度。

  1. 确定递推公式

如果s[i] == s[j],dp[i][j] = dp[i+1][j - 1] + 2。(因为i,j是从两头来的,回文一定是成对出现的)

如果不相等,考虑动i还是动j,取两者中最大的。dp[i][j] = max(dp[i +1][j],dp[i][j - 1])

  1. 初始化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]才不会被初始值覆盖。

  1. 确定遍历顺序

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

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

image

  1. 举例推导dp数组

image

最终代码:

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

这里注意j从i + 1开始,最后返回dp[0][s.size() - 1]

动态规划总结篇

动规五部曲

动规五部曲分别为:

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

在这里插入图片描述

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

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

相关文章

Mysql--技术文档--索引-《索引为什么查找数据快?》-超底层详细说明索引

索引的概念 在MySQL中&#xff0c;索引是一种数据结构&#xff0c;它被用于快速查找、读取或插入数据。索引能够极大地提高数据库查询的速度。 索引的工作方式类似于图书的索引。如果你想在图书馆找到一本书&#xff0c;你可以按照书名进行查找。书名就像是一个索引&#xf…

0012Java程序设计-springboot基于微信小程序的校园智慧帮系统的设计与实现

摘要目录相关技术2.1 MySQL数据库2.2 SpringBoot框架2.3 uniapp框架2.4 B/S架构 系统设计系统实现开发环境 摘要 随着移动互联网高速发展&#xff0c;手机、移动智能终端设备在生活中有着越来越重要的地位。在高校推崇以人为本的今天&#xff0c;也逐渐重视“移动互联网”技术…

微信小程序集成腾讯im,会话列表数据过多(长列表),卡顿问题的解决

说明 我这边用小程序集成im&#xff0c;然后结合公司的需求&#xff0c;做了一个聊天的小程序&#xff0c;在测试上线的时候没有问题&#xff0c;结果到客户那边&#xff0c;因为他们聊天的人多&#xff0c;会话列表达到了300多条&#xff0c;然后点击会话列表&#xff0c;进入…

【字符串匹配】暴力匹配算法

​ 一、暴力匹配算法原理 暴力匹配算法&#xff0c;也称为朴素字符串匹配算法&#xff0c;是一种简单但不高效的字符串匹配方法。它的原理非常直观&#xff0c;其主要思想是逐个字符地比较文本串和模式串&#xff0c;从文本串的每个可能的起始位置开始&#xff0c;依次检查是…

ESD实时监控监测系统通常包括哪些功能

ESD实时监控监测系统是一种用于监测和控制静电放电的系统。静电放电&#xff08;Electrostatic Discharge&#xff0c;ESD&#xff09;是指由于电荷的不平衡而引起的突发放电现象&#xff0c;可能对电子元器件、设备和工作环境造成损害。 ESD实时监控监测系统通常包括以下功能…

6000+药品靶点在研数据库-<查询工具推荐>

了解在研药物靶点数据对于药物研发、靶点发现和验证、药物安全性评估以及治疗策略优化都具有重要的意义&#xff0c;可以为科学家提供有价值的信息和指导。如在研药物靶点数据为药物研发提供了重要的指导。了解当前正在研究的药物靶点可以帮助科学家了解当前研究的热点领域&…

九州未来入选“AIGC算力产业全景图”

日前&#xff0c;量子位智库发布《AIGC算力全景与趋势报告》&#xff08;以下简称报告&#xff09;&#xff0c;通过广泛调研与深度分析&#xff0c;系统性分析了AIGC算力构成、产业链条&#xff0c;进一步指出了AIGC算力的五新趋势及三大阶段发展预测。其中&#xff0c;九州未…

华为云云服务器评测|初始化配置SSH连接 安装MySQL的docker镜像 安装redis以及主从搭建 7.2版本redis.conf配置文件

目录 引出初始化使用&#xff0c;SSH连接控制台设置密码和配置开放连接的端口在finalshell中建立连接 安装docker&#xff0c;运行MySQL安装docker拉取运行mysql容器 redis的拉取运行redis.conf的配置&#xff08;7.2.0版本&#xff09;准备挂载文件和运行redis的主从搭建&…

企业如何建设主数据管理体系?这篇文章说清楚了

主数据是企业核心的基本业务数据&#xff0c;数据长期存在且应用于多个系统(ERP系统、MES系统、OA系统等)系统内的编码数量成几十万个&#xff0c;并且在不断增长。由于缺乏统一的标准规范&#xff0c;各系统内由于实施商不同、使用单位不同&#xff0c;同数据在各系统内编码不…

8851-LC-MT GE 具有便于现场布线的螺丝端子

8851-LC-MT GE 具有便于现场布线的螺丝端子 例如,两个UDS-TCS提供了与基于PCI的解决方案相同的功能,该解决方案采用16通道板、螺杆终端外壳和屏蔽电缆,但成本将减少247美元(29%)。相对于镍公司基于usb的热电偶产品(usb-9211),USB-TC提供了两倍的通道,但成本降低了24%。 支持…

VB(Visual Basic)程序设计

一&#xff1a;前言 1.发展方向 1.1 学习方向 Web前端学习路线 Java学习路线 嵌入式开发学习路线 如何知道企业的需求技术&#xff1a;去招聘软件看企业的要求 前端、后端、测试、运维、UI、网络安全、游戏开发..... 1.2 学习平台 程序员视频学习平台 1.3 计算机学习资源 …

【C++漂流记】结构体的定义和使用、结构体数组、结构体指针、结构体做函数参数以及结构体中const的使用

结构体&#xff08;struct&#xff09;是C语言中一种重要的数据类型&#xff0c;它由一组不同类型的成员组成。结构体可以用来表示一个复杂的数据结构&#xff0c;比如一个学生的信息、一个员工记录或者一个矩形的尺寸等。 结构体定义后&#xff0c;可以声明结构体变量&#xf…

大数据Flink(七十三):SQL的滚动窗口(TUMBLE)

文章目录 SQL的滚动窗口(TUMBLE) SQL的滚动窗口(TUMBLE) 滚动窗口定义:滚动窗口将每个元素指定给指定窗口大小的窗口。滚动窗口具有固定大小,且不重叠。例如,指定一个大小为 5 分钟的滚动窗口。在这种情况下,Flink 将每隔 5 分钟开启一个新的窗口,其中每一条数都会划…

kubernetes——ingress

简介 ingress: 是k8s内部的一个资源对象ingress controller -> ingress控制器&#xff1a; 是k8s里启动的一个pod&#xff0c;运行的是nginx的镜像&#xff0c;实现k8s内部的service&#xff08;ClusterIP类型&#xff09;的负载均衡 ingress 和ingress controller 的关…

孙哥Spring源码第18集

第18集 refresh()-invokeBeanFactoryPostProcessor-二-ConfigurationClassPostProcessor的处理逻辑 【视频来源于&#xff1a;B站up主孙帅suns Spring源码视频】【微信号&#xff1a;suns45】 1、为什么PropertySource先处理&#xff1f; 因为Conponent A在处理的过程中 要把…

elementUI时间选择器

<template>//月选择器//:clearable"false" 去掉<div class"monthCard"><el-date-picker:clearable"false"v-model"monthValue"type"month"placeholder"选择月"change"handleChangeMonth($eve…

Linux上安装FTP

1、登录FTP&#xff0c;执行安装命令 yum -y install vsftpd 2、启动FTP服务器&#xff0c;设置开启自启动 systemctl enable vsftpd.service systemctl start vsftpd.service systemctl status vsftpd.service #查看状态, 显示active说明FTP启动成功 3、修改FTP配置文件/et…

一年省1000多话费的方法,具体操作步骤我教你了,只说一遍哟!

你还在使用手机套餐吗&#xff1f; 还在使用定向流量卡吗&#xff1f; 不管你现在使用哪种上网方式&#xff1f;都不如小编说的这种划算&#xff0c;算下来一年可以省下1000多块钱。 ​ 具体操作方法如下小编教你了&#xff0c;信不信由你&#xff1a; 1、可以通过官方客服电…

java+ssm+mysql小区疫情管理系统

项目介绍&#xff1a; 使用javassmmysql开发的小区疫情管理系统&#xff0c;系统包含超级管理员&#xff0c;系统管理员、居民用户角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;首页图表统计、管理员管理、居民管理、物资管理、诊断管理、疫苗接种、访客管理…

【网站】浏览器页面文本如何禁止和解除

2023年&#xff0c;第37周。给自己一个目标&#xff0c;然后坚持总会有收货&#xff0c;不信你试试&#xff01; 有时候&#xff0c;看法的网站&#xff0c;网页文本内容希望不能被复制&#xff0c;那么就需要对浏览器网页进行一些限制&#xff0c;是一种网站开发中的保护措施。…