动态规划-最长回文子串

news2024/12/29 3:15:50

动态规划-最长回文子串

  • 原题描述
  • 解答
    • 中心移动
      • 思想
      • 代码实现
      • 复杂度分析
        • 时间复杂度
        • 空间复杂度
    • 动态规划
      • 思想
      • 代码实现
      • 复杂度分析
        • 时间复杂度
        • 空间复杂度

突然觉得很有必要将学过的内容记录下来,这样后续在需要用到的时候就可以避免从头进行学习,而去看自己之前做过的笔记无疑是效率更高的方法。

而作为计算机专业的学生,纸质笔记无法很好的进行记录,像写代码、画图、画表都是很麻烦的,而且纸质的很容易丢,因此还是进行电子笔记记录更佳。

那么选择用博客还是云笔记呢?私以为选择更为公开的博客,可以更加驱动自己进行详细的记录和进行浅显易懂的讲解,从而避免自己某些时候滥竽充数的行为。

原题描述

5. 最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

示例 1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。

示例 2:
输入:s = “cbbd”
输出:“bb”

提示: 1 <= s.length <= 1000 s 仅由数字和英文字母组成

解答

中心移动

思想

对于这个题来说,进行最长回文子串的判断,首先想到的就是遍历所有的回文子串,然后记录最长的回文子串及其长度
那么如何遍历这些回文子串?由于回文子串的遍历需要从中心往四周进行遍历,所以需要遍历所有的回文中心,但是回文中心会有以下两种情况。

  1. 中心只有一个字符的总长度为奇数的情况,例如aba
  2. 中心会有两个字符的总长度为偶数的情况,例如abba

设i, j为中心点。那么对于中心只有一个字符的情况1来说,i=j;对于中心会有两个字符的情况2来说,j=i+1。
最长回文子串-中心移动示意图

那其实就很简单了,让i、j进行这种遍历,在遍历的时候分别设置两个指针lr进行左右的拓展,如果是回文子串就记录,否则在当下的回文中心下已经不可能有更长的回文了,进行下一次的回文中心遍历即可。

代码实现

class Solution {
public:
    string longestPalindrome(string s) {

        int len = s.length();
        if(len < 2)  // 特殊情况处理
            return s;

        int i=0, j=1;
        int maxLen = 1, startPos = 0;
        
        while(i<len-1 && j<len){
            if(s[i] == s[j]){
                int left = i-1, right = j+1;
                while(left>=0 && right<=len-1 && s[left]==s[right]){
                    left--;
                    right++;
                }
                if(right-left-1>maxLen){
                    maxLen = right-left-1;
                    startPos = left+1;
                }
            }

            if(i!=j)
                i++;
            else
                j++;
        }
        
        return s.substr(startPos, maxLen);
    }
};

这里在进行实现的时候,有进行一些小tips优化:

  1. i0开始到len-2j1开始到len-1,也就是省略了i=0,j=0i=len-1,j=len-1的情况。
    因为这两种情况其实也只能判断一个长度为1的回文子串,这种情况在中间的时候随便都能判断出来。最极端情况下,例如ab这样长度为2的非回文串,由于startPosmaxLen的设置,最后返回的也是a,不会出问题。
  2. 中途对最长的回文子串进行记录的时候,不要直接进行截断来存字符串,而是记录开始的下标和长度,这样最后只截取一次,避免性能开销。

复杂度分析

时间复杂度

令字符串长度为n,中心只有一个字符的有n种情况,中心有两个字符的有n-1种情况。总共有2n-1种中心情况。
对于每次的中心情况进行遍历的时候,由于是向两边扩展,最多不超过n/2
相乘,也就是O(n^2)的时间复杂度。

空间复杂度

没有开辟额外空间,O(1)

动态规划

动态规划说实话,在这个题目并不合适,还不如上面的中心移动的方法。因为动态规划相比来说会有额外的二维数组的空间开销。

思想

用最经典的动态规划思考方式来进行。设置一个二维数组dp[n][n],其中dp[i][j]代表s[i...j]是不是回文子串,是的话为true,不是为false

  1. 最优子结构
    s[i...j]是不是回文子串,取决于s[i+1...j-1]是不是回文子串和s[i]是否与s[j]相同。
  2. 状态转移方程

d p [ i ] [ j ] = = { d p [ i + 1 ] [ j − 1 ] , s [ i ] = = s [ j ] f a l s e , s [ i ] ! = s [ j ] dp[i][j] = = \begin{cases} dp[i+1][j-1], & s[i]==s[j]\\ false, & s[i]!=s[j] \\ \end{cases} dp[i][j]=={dp[i+1][j1],false,s[i]==s[j]s[i]!=s[j]

  1. 边界处理
    i=j的时候,长度为1,必定是回文子串,dp[i][j]=true

代码实现

class Solution {
public:
    string longestPalindrome(string s) {
        int len = s.length();
        // 特殊处理
        if(len < 2)
            return s;
        
        int maxLen = 1, begin = 0;

        vector<vector<bool>> dp(len, vector<bool>(len, false));
        for(int i=0; i<len; i++)
            dp[i][i] = true;
        
        for(int j=1; j<len; j++){
            for(int i=0; i<j; i++){ // 注意i从0开始
                if(s[i] != s[j])
                    dp[i][j] = false;
                else{
                    if(j-i < 3)
                        dp[i][j] = true;
                    else
                        dp[i][j] = dp[i+1][j-1];
                }
                if(dp[i][j] == true && j-i+1>maxLen){
                    begin = i;
                    maxLen = j-i+1;
                }
            }
        }
        return s.substr(begin, maxLen);
         
    }
};

tips:
当s[i] == s[j]的时候,先进行了j-i<3的判断,这种情况是子串的长度<=3的情况,在这种情况下s[i]=s[j],不管长度为2还是3,都是回文子串,直接返回true。

复杂度分析

时间复杂度

O(n^2)

空间复杂度

开辟了一个二维数组,O(n^2)

2024/03/31:
希望后面在刷算法题的时候能够坚持下来,在搞懂一个算法题之后通过博客的方式来做笔记,这样后面在warmup的时候很快就能上手,避免重复的0到1的思考。

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

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

相关文章

【Threejs基础教程-光影篇】5.2 Threejs 阴影系统

5.2 Threejs阴影系统 学习ThreeJS的捷径在用光影系统之前threejs是实时光影web端目前没有优质的实时光影实时光影会大幅增加渲染压力没有独显的电脑不建议添加实时光影 阴影配置什么样的灯光可以产生阴影什么样的物体可以产生阴影和接受阴影注意开启阴影渲染灵活运用阴影 平行光…

【Linux】普通用户提升权限

概述 在Linux环境下&#xff0c;给普通用户提权的方式&#xff0c;su与sudo命令&#xff0c;su是将一个普通用户登录为root&#xff0c;而sudo则是将普通用户短暂提升权限 普通用户使用$ root使用# 使用su提升权限 如果我们使用su将用户提升为root&#xff0c;此时需要输入…

计算机网络:数据链路层 - 封装成帧 透明传输 差错检测

计算机网络&#xff1a;数据链路层 - 封装成帧 & 透明传输 & 差错检测 数据链路层概述封装成帧透明传输差错检测 数据链路层概述 从数据链路层来看&#xff0c;主机 H1 到 H2 的通信可以看成是在四段不同的链路上的通信组成的&#xff0c;所谓链路就是从一个节点到相邻…

回溯算法|39.组合总和

力扣题目链接 class Solution { private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& candidates, int target, int sum, int startIndex) {if (sum > target) {return;}if (sum target) {result.push_back…

CISP考前笔记

1软件需求分析是保证软件质量的重要步骤&#xff0c;它的实施应该是在 软件定义阶段 1语句覆盖最弱&#xff0c;只需要让程序中的语句都执行一遍即可 。分支覆盖又称判定覆盖&#xff1a;使得程序中每个判断的取真分支和取假分支至少经历一次&#xff0c;即判断的真假均曾被满足…

K8S命令行可视化实验

以下为K8s命令行可视化工具的实验内容&#xff0c;相比于直接使用命令行&#xff0c;可视化工具可能更直观、更易于操作。 Lens Lens是用于监控和调试的K8S IDE。可以在Windows、Linux以及Mac桌面上完美运行。在 Kubernetes 上&#xff1a; 托管地址&#xff1a;github/lensa…

登录者个人信息查询

目录 &#x1f95e;1.vo层描述 &#x1f37f;2..vo层创建 &#x1f32d;3.编写controller层 &#x1f953;4.service层 &#x1f9c2;5.测试 1.vo层描述 Spring Boot项目中的实体类通常用于映射数据库表&#xff0c;包含了业务对象的所有属性。然而&#xff0c;前端或其…

Verilog基础【一】

文章目录 1.1 第一个verilog设计1.2 Verilog 简介1.3 Verilog环境搭建1.4 Verilog 设计方法设计方法设计流程 2.1 Verilog 基础语法格式注释标识符与关键字 2.2 Verilog 数值表示数值种类整数数值表示方法实数表示方法十进制&#xff1a;科学计数法&#xff1a; 字符串表示方法…

如何做慢查询优化?

如何做慢查询优化&#xff1f; 这个问题可以说是一个高频问题&#xff0c;总是被问到&#xff0c;今天来总结下这个问题。 慢查询&#xff0c;就是 SQL 查询中耗时比较大的一类查询&#xff0c;MySQL 提供了慢查询日志 slow_query_log&#xff0c; 它会记录耗时大于我们设置…

【Chapter2】进程、线程与作业,计算机操作系统教程,第四版,左万利,王英

文章目录 [toc] 一、多道程序设计1.1单道程序设计的缺点1.2多道程序设计的提出1.3多道程序设计存在的问题 二、进程的引入2.1进程的概念2.2进程的组成2.2.1进程控制块2.2.2程序 2.3进程的类型及特征2.3.1进程的类型2.3.2进程的特征 2.4进程的状态及转换2.4.1进程的状态创建态就…

项目亮点—动态线程池管理工具

问题 你是否在项目中使用线程池遇到过以下问题&#xff1f; 1.创建线程池核心参数不好评估&#xff0c;随着业务流量的波动&#xff0c;极有可能出现生产故障。 2.不支持优雅关闭&#xff0c;当项目关闭时&#xff0c;大量正在运行的线程池任务被丢弃。 3.不支持运行时监控…

java每日一题——分礼物(多线程运用)

前言&#xff1a; 运用了多线程的综合案例&#xff0c;顺便熟悉一下其他语法。打好基础&#xff0c;daydayup!!! 题目&#xff1a; 有100份礼物&#xff0c;小红小明同时发送&#xff0c;当剩下的礼物小于10份的时候则不再送出&#xff0c;利用多线程模拟该过程并将线程的名称…

R2GenCMN中的Encoder_Decoder结构

R2GenCMN中的 Encoder_Decoder 结构 Encoder_Decoder 结构直接关系到文本的生成&#xff0c;它结构参考的transformer的结构 我们这里主要看代码的实现&#xff0c;从视觉编码器的输出开始 1. 模型结构 首先介绍一下整体结构&#xff0c;这里的baseCMN其实就是一个包装了的T…

2024年noc指导教师认证测评参考试题题目5-6合集

[noc指导教师认证] 测评参考试题 说明:NOC教师指导认证考试题目是从题库里抽题,因此每位老师每次考试题目都不一样以下题目为测试考试时收集到的一些题目,作为辅助提供给各位老师,老师们可以记住题目及答案的具体内容 (选项顺序会变),以免考试时遇到。2024年的做的题目有的…

两张图片相似度匹配算法学习路线

大纲&#xff1a;​​​​​​目标跟踪基础&#xff1a;两张图片相似度算法-腾讯云开发者社区-腾讯云 (tencent.com) 目标跟踪基础&#xff1a;两张图片相似度算法 (qq.com) 一、传统方法 1.欧式距离&#xff08;用于判断是否完全相同&#xff09; [三维重建] [机器学习] 图…

RAG进阶笔记:RAG进阶

1 查询/索引部分 1.1 层次索引 创建两个索引——一个由摘要组成&#xff0c;另一个由文档块组成分两步进行搜索&#xff1a;首先通过摘要过滤出相关文档&#xff0c;接着只在这个相关群体内进行搜索 1.2 假设性问题 让LLM为每个块生成一个假设性问题&#xff0c;并将这些问…

一文看懂DDR1到DDR5的演变

DDR内存技术自问世以来&#xff0c;已经经历了多代的迭代和优化。每一代DDR内存都在性能、容量、功耗和功能上有所提升。以下是从DDR1到DDR5的主要区别和特点&#xff1a; DDR1 DDR1是第一代双倍数据速率同步动态随机存取存储器&#xff0c;标志着内存技术的一个重要里程碑。…

网安基础2-Sniffer的使用与防范

1. 嗅探器sniffer的工作原理 能捕获经过该网络设备的报文&#xff0c;通过分析网络流量&#xff0c;找出关键信息&#xff0c;解决网络问题。 不同于键盘捕获程序&#xff0c;如keylogger利用中断或钩子技术&#xff0c;Sniffer将网络接口置成适当的模式&#xff0c;如杂收。…

瑞吉外卖实战学习--9、mybatisPlus公共字段自动填充

mybatisPlus公共字段自动填充 前言实现步骤实体类添加注解按照框架要求编写元数据对象处理器&#xff0c;在此类中统一为公共字段赋值&#xff0c;此类需要实现MetaObjectHandler接口1、在创建和更新的时候修改创建和更新的时候自动填充时间2、如何获取到当前的id 测试结果 前言…

Vision Mamba 双向状态空间模型下的高效视觉表示学习

论文题目&#xff1a;Vision Mamba: Efficient Visual Representation Learning with Bidirectional State Space Model 双向状态空间模型下的高效视觉表示学习 论文链接&#xff1a;http://arxiv.org/abs/2401.09417 代码链接&#xff1a;https://github.com/hustvl/Vim 1、…