【经典算法】LeetCode 5: 最长回文子串(Java/C/Python3实现含注释说明,Medium)

目录

  • 题目描述
  • 思路及实现
    • 方式一:动态规划法
      • 思路
      • 代码实现
        • Java版本
        • C语言版本
        • Python3版本
      • 复杂度分析
    • 方式二:中心扩展法
      • 思路
      • 代码实现
        • Java版本
        • C语言版本
        • Python3版本
      • 复杂度分析
  • 总结
  • 相似题目

  • 标签(题目类型):回文串、动态规划

题目描述

给定一个字符串 `s`,找到其中最长的回文子串。可以假设 `s` 的最大长度为 1000。示例1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。示例2:
输入: "cbbd"
输出: "bb"

原题:LeetCode 5

思路及实现

方式一:动态规划法

思路

Dynamic Programming(DP) 动态规划是一种将问题分解成子问题并分别计算的优化技术。对于回文子串,我们可以使用动态规划来解决。

对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。例如对于字符串 “ababa”,如果我们已经知道 “bab” 是回文串,那么 “ababa” 一定是回文串,这是因为它的首尾两个字母都是 “a”。

通过定义一个二维数组 dp[i][j],表示 s 的第 i 个字符到第 j 个字符组成的子串是否为回文字符串。当 i == j 时,表示一个字符,是回文字符串,当 i + 1 == j ,则优先考虑两个字符是否相等来将问题规模缩小,同时考虑前一个子串是否为回文字符串。对于 i + 1 < j 的情况,可以通过判断 s[i] 和 s[j] 是否相等,并判断定义的 dp[i+1][j-1] 是否为回文字符串。如果是回文字符串,则 dp[i][j] 也是回文字符串。

代码实现

Java版本
class Solution {public String longestPalindrome(String s) {int n = s.length(); // 计算字符串的长度boolean[][] dp = new boolean[n][n]; // 创建一个二维数组用于记录子串是否为回文串String ans = ""; // 初始化最长回文子串为空字符串// 遍历所有长度的子串for (int len = 1; len <= n; len++) {// 遍历子串的起始位置for (int i = 0; i + len - 1 < n; i++) {int j = i + len - 1; // 子串的结束位置if (len == 1) {dp[i][j] = true; // 单个字符必定是回文串} else if (len == 2) {dp[i][j] = (s.charAt(i) == s.charAt(j)); // 只有两个字符时判断是否相等} else {dp[i][j] = (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]); // 多于两个字符时判断首尾字符是否相等}if (dp[i][j] && len > ans.length()) { // 如果当前子串是回文串并且长度更长ans = s.substring(i, j + 1); // 更新结果为当前子串}}}return ans;}
}

说明:
longestPalindrome 方法用于寻找给定字符串中的最长回文子串。使用动态规划的思想,创建一个二维数组 dp,其中 dp[i][j] 表示从索引 i 到索引 j 的子串是否为回文串。
通过遍历所有长度的子串,以及遍历子串的起始位置,判断子串是否为回文串,并根据回文串的长度更新最长回文子串 ans。
当子串的长度为 1 时,即一个字符,必定是回文串。
当子串的长度为 2 时,判断首尾两个字符是否相等。
当子串的长度大于 2 时,判断首尾两个字符是否相等,并根据 dp[i+1][j-1] 的结果判断子串是否为回文串。
如果当前子串是回文串,并且长度比之前记录的最长回文子串长度更长,则更新最长回文子串 ans。
最后,返回最长回文子串。

C语言版本

char* longestPalindrome(char* s) {int n = strlen(s); // 计算字符串的长度bool dp[n][n]; // 创建一个二维数组用于记录子串是否为回文串memset(dp, false, sizeof(dp)); // 初始化dp数组为falsechar* ans = ""; // 初始化最长回文子串为空字符串// 遍历所有长度的子串for (int len = 1; len <= n; len++) {// 遍历子串的起始位置for (int i = 0; i + len - 1 < n; i++) {int j = i + len - 1; // 子串的结束位置if (len == 1) {dp[i][j] = true; // 单个字符必定是回文串} else if (len == 2) {dp[i][j] = (s[i] == s[j]); // 只有两个字符时判断是否相等} else {dp[i][j] = (s[i] == s[j] && dp[i + 1][j - 1]); // 多于两个字符时判断首尾字符是否相等}if (dp[i][j] && len > strlen(ans)) { // 如果当前子串是回文串并且长度更长char* sub = (char*)malloc((len + 1) * sizeof(char)); // 分配内存保存当前子串strncpy(sub, s + i, len); // 复制当前子串到内存中sub[len] = '\0'; // 添加字符串结束标志ans = sub; // 更新结果为当前子串}}}return ans;
}

说明: (同上)
longestPalindrome 函数用于寻找给定字符串中的最长回文子串。使用动态规划的思想,创建一个二维数组 dp,用于记录子串是否为回文串。
通过遍历所有长度的子串,以及遍历子串的起始位置,判断子串是否为回文串,并根据回文串的长度更新最长回文子串 ans。
子串的判断分三种情况:
当子串的长度为 1 时,即一个字符,必定是回文串。
当子串的长度为 2 时,判断首尾两个字符是否相等。
当子串的长度大于 2 时,判断首尾两个字符是否相等,并根据 dp[i+1][j-1] 的结果判断子串是否为回文串。
如果当前子串是回文串,并且长度比之前记录的最长回文子串长度更长,则更新最长回文子串 ans。
最后,返回最长回文子串。

Python3版本
class Solution:def longestPalindrome(self, s: str) -> str:n = len(s)dp = [[False] * n for _ in range(n)]ans = ""# 遍历所有长度的子串for length in range(1, n + 1):# 遍历子串的起始位置for i in range(n - length + 1):j = i + length - 1  # 子串的结束位置if length == 1:dp[i][j] = True  # 单个字符必定是回文串elif length == 2:dp[i][j] = (s[i] == s[j])  # 只有两个字符时判断是否相等else:dp[i][j] = (s[i] == s[j] and dp[i + 1][j - 1])  # 多于两个字符时判断首尾字符是否相等if dp[i][j] and length > len(ans):  # 如果当前子串是回文串并且长度更长ans = s[i:j + 1]  # 更新结果为当前子串return ans

说明: (同上)
longestPalindrome 方法用于寻找给定字符串中的最长回文子串。使用动态规划的思想,创建一个二维数组dp,其中dp[i][j]表示从索引i到索引j的子串是否为回文串。通过遍历所有长度的子串,从最短的子串起,依次判断是否为回文串,并根据判断结果更新最长回文子串。最后,返回最长回文子串。
dp[i][j]的判断依据如下:
当子串长度为1时,dp[i][j]为True,因为单个字符必定是回文串;
当子串长度为2时,子串为回文串的条件是s[i]和s[j]相等;
当子串长度大于2时,子串为回文串的条件是首尾字符相等且去除首尾字符的子串也为回文串。
当发现一个更长的回文子串时,将其更新为结果。

复杂度分析

  • 时间复杂度:该算法的时间复杂度为 O(n^2),其中 n 是字符串的长度。双重循环遍历了所有长度为 1 到 n 的子串。
  • 空间复杂度:该算法的空间复杂度为 O(n^2),存储了一个二维数组 dp。

方式二:中心扩展法

思路

中心扩展法的基本思路是从左至右遍历字符串,以当前字符和其相邻字符为中心,向两边扩展,判断是否为回文串。在判断时,可以将回文串的起始和结束位置保存下来。

从每一个位置出发,向两边扩散即可。遇到不是回文的时候结束。举个例子,str=acdbbdaa 我们需要寻找从第一个 b(位置为 3)出发最长回文串为多少。怎么寻找?
首先往左寻找与当期位置相同的字符,直到遇到不相等为止。
然后往右寻找与当期位置相同的字符,直到遇到不相等为止。
最后左右双向扩散,直到左和右不相等。如下图所示:
在这里插入图片描述
每个位置向两边扩散都会出现一个窗口大小(len)。如果 len>maxLen(用来表示最长回文串的长度)。则更新 maxLen 的值。
因为我们最后要返回的是具体子串,而不是长度,因此,还需要记录一下 maxLen 时的起始位置(maxStart),即此时还要 maxStart=len。

代码实现

Java版本
class Solution {public String longestPalindrome(String s) {int start = 0; // 回文串的起始位置int end = 0; // 回文串的结束位置for (int i = 0; i < s.length(); i++) {int len1 = expandAroundCenter(s, i, i); // 以当前字符为中心的回文串长度int len2 = expandAroundCenter(s, i, i + 1); // 以当前字符和下一个字符为中心的回文串长度int len = Math.max(len1, len2); // 取较长的回文串长度if (len > end - start) {start = i - (len - 1) / 2; // 更新回文串的起始位置end = i + len / 2; // 更新回文串的结束位置}}return s.substring(start, end + 1); // 根据起始位置和结束位置返回最长回文子串}private int expandAroundCenter(String s, int left, int right) {while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {left--; // 向左扩展right++; // 向右扩展}return right - left - 1; // 返回回文串的长度}
}

说明:
longestPalindrome 方法用于寻找给定字符串中的最长回文子串。根据中心扩展法的思想,遍历字符串中的每个字符,以当前字符为中心向两边扩展,同时以当前字符和下一个字符为中心向两边扩展,获取回文串的长度。通过比较回文串的长度,不断更新最长回文串的起始位置和结束位置。最后,根据起始位置和结束位置从原字符串中截取出最长回文子串并返回。
expandAroundCenter 方法用于以指定的左右位置为中心向两边扩展,判断是否为回文串。通过比较左右位置的字符是否相等,并同时向左和向右移动位置来不断扩展回文串的长度。最后,返回回文串的长度。

C语言版本
char* longestPalindrome(char* s) {int len = strlen(s);int start = 0;int end = 0;for (int i = 0; i < len; i++) {int len1 = expandAroundCenter(s, i, i);int len2 = expandAroundCenter(s, i, i + 1);int len = len1 > len2 ? len1 : len2;if (len > end - start) {start = i - (len - 1) / 2; // 更新回文串起始位置end = i + len / 2; // 更新回文串结束位置}}char *longest_palindrome = malloc((end - start + 2) * sizeof(char));strncpy(longest_palindrome, s + start, end - start + 1); // 复制回文串至新分配的内存longest_palindrome[end - start + 1] = '\0';return longest_palindrome;
}int expandAroundCenter(char *s, int left, int right) {while (left >= 0 && right < strlen(s) && s[left] == s[right]) {left--; // 向左扩展right++; // 向右扩展}return right - left - 1; // 返回回文串的长度
}

说明:
longestPalindrome 函数用于寻找给定字符串中的最长回文子串。通过遍历字符串并以每个字符为中心依次判断以该字符或相邻两个字符为中心的回文串长度。通过比较回文串的长度,不断更新最长回文串的起始位置和结束位置。最后,将最长回文串从原字符串复制到新分配的内存中并返回。
expandAroundCenter 函数用于在给定字符串中以指定的左右位置为中心向两边扩展,判断是否为回文串。通过比较左右位置的字符是否相等,并同时向左和向右移动位置来不断扩展回文串的长度。最后,返回回文串的长度。

Python3版本
class Solution:def longestPalindrome(self, s: str) -> str:start = 0end = 0for i in range(len(s)):len1 = self.expandAroundCenter(s, i, i)len2 = self.expandAroundCenter(s, i, i + 1)length = max(len1, len2)if length > end - start:start = i - (length - 1) // 2 # 更新回文串起始位置end = i + length // 2 # 更新回文串结束位置return s[start: end + 1] # 根据起始位置和结束位置返回最长回文子串def expandAroundCenter(self, s: str, left: int, right: int) -> int:while left >= 0 and right < len(s) and s[left] == s[right]:left -= 1 # 向左扩展right += 1 # 向右扩展return right - left - 1 # 返回回文串的长度
}

说明:
longestPalindrome 函数用于寻找给定字符串中的最长回文子串。通过遍历字符串并以每个字符为中心或相邻两个字符为中心依次判断以该中心为起点的回文串长度。通过比较回文串的长度,不断更新最长回文串的起始位置和结束位置。最后,根据起始位置和结束位置从原字符串中截取出最长回文子串并返回。
expandAroundCenter 函数用于在给定字符串中以指定的左右位置为中心向两边扩展,判断是否为回文串。通过比较左右位置的字符是否相等,并同时向左和向右移动位置来不断扩展回文串的长度。最后,返回回文串的长度。

复杂度分析

  • 时间复杂度:该算法的时间复杂度为 O(n^2),其中 n 是字符串的长度。在中心扩展法中,每个字符仅遍历一次。
  • 空间复杂度:该算法的空间复杂度为 O(1),只使用了常量级的额外空间。

总结

方式备注优点缺点时间复杂度空间复杂度
动态规划法通过动态规划计算回文子串算法稳定可靠需要额外的二维数组存储状态O(n^2)O(n^2)
中心扩展法通过扩展中心位置计算回文子串具有较高效率对空间的使用较低O(n^2)O(1)

相似题目

(表格形式,列举出)

相似题目难度链接
两个数组的交集简单leetcode-349

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

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

相关文章

【C++】unordered 系列关联式容器

文章目录 1. unordered 系列关联式容器2. unordered_map2.1 unordered_map 的文档介绍2.2 unordered_map 的接口说明 3. unordered_set4. 在线 OJ 1. unordered 系列关联式容器 在 C 98 中&#xff0c;STL 提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可…

mybatis(4) 代理机制以及小技巧

mybatis 1、 问题2、使用3、#与$3.1 例子3.2什么情况下必须使用${} 4、别名机制5 、Mapper配置6、配置模板文件7、使用自动生成的主键 1、 问题 在上一篇mybtis的web项目中&#xff0c;我们最后有一个问题没有解决&#xff0c;就是dao的实现类&#xff0c;其代码很类似&#x…

Mybase 8.x 下载安装试用详细教程(Windows)

一、软件介绍 MyBase是一款本地笔记软件&#xff0c;它能够帮助你管理和组织大量的信息。 二、下载安装 下载&#xff1a;点我去下载页面 Mybase 软件目前主要实现了两种版本&#xff1a;Mybase Desktop (桌面版) 和 Mybase Server (网络版)&#xff1a; 桌面版软件运行于 …

零售行业数字化广告评价标准 - 《IAB/MRC零售(广告)测量指南》

IAB/MRC零售&#xff08;广告&#xff09;测量指南 --- 最新标准&#xff0c;2024年1月发布 目录 1出台此标准的目的是什么&#xff1f;2标准宗旨3本标准的主要关键领域4为什么这对品牌和零售商很重要5能给零售媒体中小型玩家带来什么机会&#xff1f;6评价零售媒体效果的最…

金仓数据库Kingbase的数据库开发管理工具KStudio连接乱码

背景&#xff1a; 金仓数据库V8R6&#xff0c;KStudio在Windows10上运行&#xff0c;JDK8 问题&#xff1a; 使用客户端连接数据库时&#xff0c;提示信息乱码&#xff0c;首选项设置字符集不管用&#xff0c;具体如下图所示&#xff1a; Before&#xff1a; After&#xff1…

【CPA考试】2024注册会计师报名照片尺寸要求解读及手机拍照方法

随着2024年注册会计师考试的临近&#xff0c;众多会计专业人士和学生都开始准备报名参加这一行业的重要考试&#xff0c;报名时间为4月8日至4月30日。报名过程中&#xff0c;一张符合要求的证件照是必不可少的。本文将为您详细解读2024年注册会计师考试报名照片的尺寸要求&…

sfml sdl2 windows vscode 调试和coderunner插件运行

链接库写在编译链接命令里&#xff0c;如果没有使用到不会加入到生成的可执行文件里。所以tasks.json可以这样写&#xff0c; {"version": "2.0.0","tasks": [{"type": "cppbuild","label": "C/C: g.exe 生…

GlusterFS分布式文件系统

一、GlusterFS简介 GlusterFS 是一个开源的分布式文件系统。由存储服务器、客户端以及NFS/Samba存储网关(可选&#xff0c;根据需要选择使用)组成。没有元数据服务器组件&#xff0c;这有助于提升整个系统的性能、可靠性和稳定性 二、GlusterFS特点 2.1 扩展性和高性能 Glu…

结合 linux 0.11 源码分析为什么 fork 函数会返回两个值

#&#xff08;1&#xff09;学习资料是这些书 以及赵炯博士的完全剖析。谢谢这些大师与网上优秀的文章。 #&#xff08;2&#xff09;看 linux 0.11 源码是 sourceinlight 4.这里附上一个安装包。 由本图可知&#xff0c; main 函数对 fork 函数的调用。 fork 函数实际是定…

掌握苹果电脑保养秘籍,全方位维护指南!

苹果电脑&#xff08;Mac&#xff09;凭借卓越的性能表现、精致的设计美学以及深入人心的操作系统体验赢得了全球用户的高度评价。不过&#xff0c;无论是哪款顶级配置的Mac产品&#xff0c;都需要经过适时且恰当的保养维护&#xff0c;才能持续展现最优性能。 苹果电脑维护小…

最新AI工具系统ChatGPT网站运营源码SparkAi系统V6.0版本,GPTs应用、AI绘画、AI换脸、垫图混图、Suno-v3-AI音乐生成大模型全支持

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧。已支持GPT…

Django之五种中间件定义类型—process_request、process_view、process_response.......

目录 1. 前言 2. 基础中间件 3. 如何自定义中间件 4. 五种自定义中间件类型 4.1 process_request 4.2 process_view 4.3 process_response 4.4 process_exception 4.5 process_template_response 5. 最后 1. 前言 哈喽&#xff0c;大家好&#xff0c;我是小K,今天咋们…

window安装maven和hadoop3.1.4

前面的文章已讲解如何安装idea和进行基本设置&#xff0c;本文主要带着大家安装配置好maven和hadoop. 大家不用去官网下载&#xff0c;直接使用我发给大家的压缩文件&#xff0c;注意解压后的文件夹不要放在中文目录下&#xff0c;课堂上我们讲解过原因。 这是我电脑上的路径&a…

App Inventor 2 SQLite 拓展

SQLite 拓展 此SQLite 拓展由中文网开发及维护&#xff0c;与 TaifunSQLite 功能类似&#xff0c;但TaifunSQLite是收费的&#xff0c;美刀。 文档及拓展下载地址&#xff1a; App Inventor 2 SQLite 拓展&#xff1a;超流行兼容主流SQL语法的迷你本地数据库引擎 App Invento…

018——红外遥控模块驱动开发(基于HS0038和I.MX6uLL)

目录 一、 模块介绍 1.1 简介 1.2 协议 二、 驱动代码 三、 应用代码 四、 实验 五、 程序优化 一、 模块介绍 1.1 简介 红外遥控被广泛应用于家用电器、工业控制和智能仪器系统中&#xff0c;像我们熟知的有电视机盒子遥控器、空调遥控器。红外遥控器系统分为发送端和…

【SCI绘图】【热力图系列1 R】多特征相关性分析热力图R语言实现

SCI&#xff0c;CCF&#xff0c;EI及核心期刊绘图宝典&#xff0c;爆款持续更新&#xff0c;助力科研&#xff01; 本期分享&#xff1a; 【SCI绘图】【热力图系列1 R】多特征相关性分析热力图R语言实现 1.环境准备 library(gplots) library(RColorBrewer) 2.数据示例 ###…

宠物医院管理系统

文章目录 宠物医院管理系统一、系统演示二、项目介绍三、12000字论文参考四、系统部分页面展示五、部分代码展示六、底部获取项目源码和万字论文参考&#xff08;9.9&#xffe5;带走&#xff09; 宠物医院管理系统 一、系统演示 宠物医院管理系统 二、项目介绍 语言&#xf…

基于YOLOv8的GC10-DET缺陷检测系统(Python源码+Pyqt6界面+数据集)

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文摘要&#xff1a;基于YOLOv8的GC10-DET缺陷检测系统&#xff0c;并阐述了整个数据制作和训练可视化过程&#xff0c;最后通过Pyside UI界面进行展示。 博主简介 AI小怪兽&#xff0c;YOLO骨灰级玩家&#xff0c;1&#xff09;YOL…

JAVA并发编程(二)_线程池

JAVA线程池 1.1Java 线程池之 Executor 框架 为了实现线程池和管理线程池&#xff0c;JDK 给我们提供了基于 Executor 接口的一系列接口、抽象类、实现类&#xff0c;我们把它称作线程池的 Executor 框架&#xff0c;Executor 框架本质上是一个线程池&#xff1b; ​ Java 线…

Python的基础知识学习路线1—python简介与环境配置(最全路线,每部分附有代码操作结果)

一、Python简介 &#xff08;1&#xff09;发展史 Python是由创始人贵铎范罗萨姆&#xff08;Guido van Rossum&#xff09;在阿姆斯特丹于1989年圣诞节期间&#xff0c;为了打发圣诞节的无趣&#xff0c;开发的一个新的解释型脚本语言。之所以选中Python&#xff08;大蟒蛇的…