【leetcode 力扣刷题】回文串相关题目(KMP、动态规划)

news2024/12/30 2:58:42

回文串相关题目

  • 5. 最长回文子串
    • 动态规划
    • 中心扩展算法
  • 214. 最短回文串
  • 336. 回文对

5. 最长回文子串

题目链接:5. 最长回文子串
题目内容:在这里插入图片描述
题目就是要我们找s中的回文子串,还要是最长的。其实想想,暴力求解也行……就是遍历所有的子串,同时判断是不是回文串,是的话再和记录的最大长度maxlen比较,如果更长就更新。时间复杂度直接变成O(n^3)。

动态规划

优化的点在于,假设子串s[i~j]已经不是回文串了,s[i-1~j+1]也不是回文串,就不用再去判断是否是回文串了。用动态规划求解,dp[i][j]为true或者false,表示s[i~j]子串是or不是回文串,dp更新过程:

  • dp[i][j] = true需要dp[i+1][j-1] = true同时s[i] = s[j];【注意i+1 >= j-1】
  • 如果dp[i+1][j-1] = false,dp[i][j]直接为false;
  • 如果s[i] != s[j],直接false;
  • dp[i][i] = true;
    代码实现(C++):
class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        //如果s是空或者只有一个字符直接返回s,本身就是回文串
        if(n < 2)
            return s;
         //dp记录s所有子串是否是回文串
        vector<vector<bool>> dp(n,vector<bool>(n));
        //单字符子串s[i]是回文串
        for(int i = 0; i < n ; i++)
            dp[i][i] = true;
        //记录目前最长的子串长度和开始的下标
        int maxLen = 1, idx = 0;
        //L是子串的长度,按照长度来找子串
        for(int L = 2; L <= n; L++){
        	//子串开始下标
            for(int begin = 0; begin <= n-L; begin++){
            	//子串结束下标
                int end = L - 1 + begin;
                //判断当前子串是否是回文子串
                if(s[begin] != s[end])
                    dp[begin][end] = false;
                else{
                    if(L <= 3)
                        dp[begin][end] = true;
                    else
                        dp[begin][end] = dp[begin+1][end-1];
                }
				//如果当前子串是回文子串,其长度和maxlen对比
                if(dp[begin][end] && L > maxLen){
                    maxLen = L;
                    idx = begin;
                }
            }
        }
        //返回最长回文子串
        return s.substr(idx, maxLen);
    }
};

动态规划也是判断所有子串是否是回文串,但是相较于暴力求解,用dp来存储每个子串是否是回文串,一个子串s[i~j]是否是回文串可以直接通过dp[i+1][j-1]得到,时间复杂度是O(1),因此整体时间复杂度是O(n^2)。同时dp需要额外的空间,空间复杂度是O(n^2)。
注意上述遍历子串,最外层是通过子串长度来控制的,如果外层是子串开始下标begin,内层是子串结束下标end,dp[begin][end]根据dp[begin+1][end-1]决定是true还是false,需要先有dp[begin+1][end-1],即dp[begin+1]这一行要先求得值,begin要从大到小:

//注意begin从大到小,从后往前
for(int begin = n - 2; begin >= 0; begin --){
    for(int end = begin + 1; end < n; end ++){
        if(s[begin] != s[end])
            dp[begin][end] = false;
        else{
            if(end - begin < 3)
                dp[begin][end] = true;
            else
                dp[begin][end] = dp[begin+1][end-1];
        }
        if(dp[begin][end] && end - begin + 1 > maxLen){
            maxLen = end - begin + 1;
            idx = begin;
        }
    }
}

中心扩展算法

动态规划需要dp来存储所有子串是否是回文串,其实是并不需要的。如果以一个字符串作为中心,然后朝两边扩展,s[i~j]变成s[i-1~j+1],s[i-1~j+1]是否是回文串直接依赖于s[i~j]的,如果s[i~j]不是回文串了,再朝两边扩展是没有意义的。这样减少了部分子串的判断,同时减少了dp这个二维数组。当s[i~j]不能朝两边扩展的时候,当前的s[i~j]就是以某个字符为中心的最长的回文子串,此时与maxlen比较,判断是否更新maxlen即可。
这样的中心就是s中的n个字符。但是需要注意的是,如果只是以这个字符作为中心,从s[i~i]开始,,遍历的永远都是长度为奇数的子串。还需要遍历长度为偶数的子串,即从s[i~i+1]这样的子串开始。代码如下(C++):

class Solution {
public:
	//查找以一个字符或者两个字符为中心的最长回文子串
    pair<int, int> expandAroundCenter(const string& s, int left, int right) {
        while (left >= 0 && right < s.size() && s[left] == s[right]) {
            --left;
            ++right;
        }
        //返回左右下标
        return {left + 1, right - 1};
    }

    string longestPalindrome(string s) {
        int start = 0, end = 0;
        //所有字符都作为中心字符去查找最长的回文子串
        for (int i = 0; i < s.size(); ++i) {
            auto [left1, right1] = expandAroundCenter(s, i, i);
            auto [left2, right2] = expandAroundCenter(s, i, i + 1);
            //更新
            if (right1 - left1 > end - start) {
                start = left1;
                end = right1;
            }
            //更新
            if (right2 - left2 > end - start) {
                start = left2;
                end = right2;
            }
        }
        return s.substr(start, end - start + 1);
    }
};

这里时间复杂度也是O(n^2),但是提交的时候运行时间,比动态规划少了20倍……
在这里插入图片描述

214. 最短回文串

题目链接:214. 最短回文串
题目内容:
在这里插入图片描述
题目的意思是要在字符串s的前面添加字符(字符数量≥1,可以说是加一个字符串s’),添加字符的目的是为了让s变成一个回文串。 另外需要最终的s’+s是所有答案中的最短的,也就是要添加的s’最短。
要使得s’+s是回文串很简单,直接把s的逆序加在s的前面,肯定是个回文串;或者把s第一个字符后的子串逆序加在s前,也肯定是回文串,是以s首字符为回文中心的。
在这里插入图片描述
上面的方法是可以得到回文串的,但是要怎么样才能使得最终的回文串更短呢。
回文串有一个回文中心,回文中心两边是长度相等的、一段的逆序与另外一段完全相同的两段子串。现在在s的前面加一些字符能够使得s’+s是回文串,那么反过来想,删除s中末尾一段与s’的逆序相同的子串,剩下的子串也是回文串。 所以只要能够在s中找到一段以s首字符开始的最长的回文串,就能保证在此基础上,将s中除这个回文子串剩下的子串,逆序加在s前面得到的回文串是最短的。
在这里插入图片描述那么我们要怎么寻找s中是回文的前缀呢?假设这个回文子串是s1,s除s1外的子串s-s1用s2表示,s^是s的逆序(反转)后的字符串,s1在s^中其实就是后缀,由于s1是回文串,所以s1 = reverse(s1)。所以把s^看作是查找串,s看作是模式串,两者其做字符串匹配,用kmp算法,最终当s^遍历到最后一个字符的时候,s是第i个字符,那么0~i这段子串就是s1,即最长的前缀回文串:
在这里插入图片描述
整体解题步骤是:

  • 找s1:s反转后的字符串s^作为查找串,s作为模式串,用kmp算法去做字符串匹配;算法结束的时,即遍历到s^最后一个字符时,对应s中第i个字符,0~i即为查找的最长前缀回文串;
  • 将s-s1反转,并加在s前面,即得到了答案;
    代码实现(C++):
class Solution {
public:
    int strStr(string haystack, string needle) {
        
        int n = needle.size();
        vector<int>  next(n, 0);
        //next数组中存的是对应下标处子串【包括下标位置】的最长前后缀的长度
        for(int i = 1; i < n; i++){
            int j = next[i-1];
            while(j>0 && needle[j] != needle[i])
                j = next[j-1];
            if(needle[i] == needle[j])
                j++;
            next[i] = j;
        }

        int pos = 0, j = 0;
        while(pos < haystack.size()){
            while(j>0 && haystack[pos] != needle[j])
                j = next[j-1];
            if(haystack[pos] == needle[j]){
                pos++;
                j++;
            } 
            else
                pos++;                  
        }
        //循环结束时,pos=haystack.size(), j对应子串长度,而不是结束下标,下标为j-1
        return j;
    }

    string shortestPalindrome(string s) {
        //s为空或者只有一个字符的时候,直接返回
        if(s.empty() || s.size() == 1)
            return s;
        string re_s = s;
        reverse(re_s.begin(),re_s.end()); //得到s的逆序re_s
        //idx其实是前缀回文子串s1的长度
        int idx = strStr(re_s,s);
        //即s一整个是回文串
        if(idx == s.size())
            return s;
        //反转s2,实际就是re_s前面一截,并加在s前面
        return re_s.substr(0, s.size() - idx) + s;
    }
};

这道题目在找s中最长前缀回文串的时候,没有使用上面题目的动态规划,是因为本题很明确,这个回文串是s的前缀,是从s第一个字符开始的子串。而要找s的最长回文子串,这个子串开始的位置是不知道的。
另外,如果题目换成在s的后面加上s’,使得s+s’是最短回文串,同样的方法,不过kmp的时候,s是查找串,s^是模式串。

336. 回文对

题目链接:336. 回文对
题目内容:
在这里插入图片描述
理解题意,是要在words中找到两个字符串words[i]、words[j],使得words[i] + words[j]是回文串。这题目不是和上面题目很像嘛!可以分情况讨论:

  • words[i]和words[j]互为对方的逆序,比如words[i] = “abcd”,words[j] =“dcba”,那么words[i] + words[j]和words[j] + words[i]都是回文的;
  • words[i]前缀本身是回文,words[j]是words[i]以回文前缀下标结束点m为开始的后缀的逆序,那么words[j] + words[i]是回文的;比如words[i] = “abcbadef”,words[j] = “fed"或者"fed”;
  • words[i]后缀本身是回文,words[j]是words[i]中回文后缀下标开始点m为结束的前缀的逆序,那么words[i] + words[j]是回文的;比如words[i] = “defabcba”,words[j] = “fed”;

还没做,代码待更……

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

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

相关文章

系统移植MakefileREADME文件分析

Makefile # 指定交叉编译工具链前缀变量 CROSS_COMPILE arm-linux-gnueabihf- #指定文件名字变量 NAME interface ## #-g:编译时添加gdb调试信息 -marm: 将程序编译生成arm指令集 -Wall:编译时显示所有警告信息 #-O0:编译时添加优化等级 -O0:不优化 -O1:一级优化 #-f…

zabbix配置钉钉告警、和故障自愈、监控java

文章目录 1.配置钉钉告警server 配置web界面创建媒介给用户添加媒介测试告警 实现故障自愈功能监控Javazabbix server 安装java gateway配置 Zabbix Server 支持 Java gateway使用系统内置模板监控 tomcat 主机 1.配置钉钉告警 server 配置 钉钉告警python脚本 脚本1 cd /…

实相融、云启未来,智慧公厕让城市生活更美好

现代社会&#xff0c;随着科技的不断发展&#xff0c;人们对于城市生活的要求也在不断提升。在这个过程中&#xff0c;智慧公厕作为城市基础设施中的重要组成部分&#xff0c;正在发挥着越来越重要的作用。通过数字化、云管理、人工智能等未来的科技方式&#xff0c;智慧公厕为…

2024字节跳动校招面试真题汇总及其解答(一)

1. 【算法题】重排链表 给定一个单链表 L 的头节点 head ,单链表 L 表示为: L0 → L1 → … → Ln - 1 → Ln请将其重新排列后变为: L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 示例 1: 输入:hea…

嵌入式Linux驱动开发(同步与互斥专题)(二)

一、自旋锁spinlock的实现 自旋锁&#xff0c;顾名思义&#xff1a;自己在原地打转&#xff0c;等待资源可用&#xff0c;一旦可用就上锁霸占它。 ① 原地打转的是CPU x&#xff0c;以后CPU y会解锁&#xff1a;这涉及多个CPU&#xff0c;适用于SMP系统&#xff1b; ② 对于单…

【Vue】Router路由无法跳转问题整理

问题集 整理了部分Vue Router路由无法跳转问题&#xff1a; 顶层router-view只能被顶层路由配置内容使用&#xff1a;此问题异常表现在路由跳转但页面不变子路由跳转必需父路由对应的组件中存在router-view&#xff1a;此问题异常表现在路由跳转但页面不变 子路由配置路径会自…

uniapp项目实践总结(十三)封装文件操作方法

导语&#xff1a;在日常 APP 开发过程中&#xff0c;经常要进行文件的保存、读取列表以及查看和删除文件等操作&#xff0c;接下来就看一下具体的方法。 目录 原理分析方法实现实战演练案例展示 原理分析 主要是以下 API。 uni.saveFile&#xff1a;保存文件到本地缓存列表…

处理流程设计-系统设计-人机界面设计

处理流程设计-系统设计-人机界面设计 流程表示工具&#xff08;重点&#xff09; 流程表示工具&#xff08;重点&#xff09; 数据流图也是一种 IPO 图 NS图和PAD图

为什么说电子元器件采购如果不够专业就容易上当受骗

电子元器件采购如果不够专业就容易上当受骗的原因有多方面&#xff0c;主要包括以下几点&#xff1a; 众多供应商和产品&#xff1a;电子元器件市场涉及众多供应商和各种不同的产品。如果采购人员不具备足够的专业知识和经验&#xff0c;可能会难以识别哪些供应商和产品是可信赖…

flink 写入数据到 kafka 后,数据过一段时间自动删除

版本 flink 1.16.0kafka 2.3 流程描述&#xff1a; flink利用KafkaSource&#xff0c;读取kafka的数据&#xff0c;然后经过一系列的处理&#xff0c;通过KafkaSink&#xff0c;采用 EXACTLY_ONCE 的模式&#xff0c;将处理后的数据再写入到新的topic中。 问题描述&#xff1…

【SpringMVC]获取参数的六种方式

目录 1.通过ServletAPI获取 2.通过控制器方法的形参获取 3.RequestParam&#xff1a;将请求参数和控制器方法的形参绑定 4.RequestHeader&#xff1a;将请求头信息与控制器方法的形参的值进行绑定 5. CookieValue&#xff1a;将cookie数据和控制器方法的形参绑定 Cookie&…

入门人工智能 —— 学习一门编程语言 python 基础代码编写和运算符介绍(1)

入门人工智能 —— 学习一门编程语言 python&#xff08;1&#xff09; 入门流程1.安装pythonwindowslinux ubuntu 代码编写打印输出结果 基本加减法介绍基本运算符 随着人工智能技术的快速发展&#xff0c;越来越多的年轻人开始关注这个领域。作为入门者&#xff0c;学习人工智…

文心一言 VS 讯飞星火 VS chatgpt (88)-- 算法导论8.3 1题

一、用go语言&#xff0c;参照图 8-3 的方法&#xff0c;说明 RADIX-SORT在下列英文单词上的操作过程:COW&#xff0c;DOG&#xff0c;SEA&#xff0c;RUG&#xff0c;ROW&#xff0c;MOB&#xff0c; BOX&#xff0c; TAB&#xff0c; BAR&#xff0c; EAR&#xff0c;TAR&…

Java基于 SpringBoot 的车辆充电桩系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 1、效果演示效果图技术栈 2、 前言介绍&#xff08;完整源码请私聊&#xff09;3、主要技术3.4.1 …

AI人工智能Mojo语言:AI的新编程语言

推荐&#xff1a;使用 NSDT场景编辑器 快速搭建3D应用场景 Mojo的主要功能包括&#xff1a; 类似Python的语法和动态类型使Python开发人员易于学习Mojo&#xff0c;因为Python是现代AI / ML开发背后的主要编程语言。使用Mojo&#xff0c;您可以导入和使用任何Python库&#xf…

2.8 PE结构:资源表详细解析

在Windows PE中&#xff0c;资源是指可执行文件中存放的一些固定不变的数据集合&#xff0c;例如图标、对话框、字符串、位图、版本信息等。PE文件中每个资源都会被分配对应的唯一资源ID&#xff0c;以便在运行时能够方便地查找和调用它们。PE文件中的资源都被组织成一个树形结…

“链主品牌”竞争战略四大误区

在《财富》500 强企业名单中&#xff0c;2008 年中国企业仅有 37 家&#xff0c;而 2019 年攀升至 119 家&#xff0c;与美国仅相差两家。2008 年&#xff0c;中国关注的问题是其在世界 500 强榜单上的企业数量太少。而如今的讨论则集中在为何中国企业规模大却实力不强。原因在…

有哪些做流程图的软件?分享一些制作方法和注意事项

流程图是一种常用的图表&#xff0c;可以用于表示各种工作流程、系统架构、决策流程等。在现代工作生活中&#xff0c;制作流程图已经成为了必备的技能之一。本文将介绍一些常用的做流程图的工具&#xff0c;并分享一些制作方法和注意事项。 做流程图的工具 1.迅捷画图&#x…

Node.js安装教程图文详解

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 下载Node.js 请下载Node.js并保存至本地&#xff0c;官方网址&#xff1a;https://nodejs.org/zh-cn/ 在此&#xff0c;选择windows系统64位的16.13.1版本进行下载。 下载…

【SLAM】Sophus库的超详细解析

在视觉SLAM中&#xff0c;李群李代数是描述位姿比较常用的一种表达形式。但是&#xff0c;在Eigen中并不提供对它的支持&#xff0c;一个较好的李群和李代数的库是Sophus库&#xff0c;它很好的支持了SO3、so3、SE3、se3。 Sophus简介 代码仓库&#xff1a;https://github.com…