LeetCode第五题:最大回文子串【5/1000 python】

👤作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。
会一些的技术:数据分析、算法、SQL、大数据相关、python
作者专栏每日更新:
LeetCode解锁1000题:打怪升级之旅
python数据分析可视化:企业实战案例
备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级

“最长回文子串”是一个经典而广为人知的问题,它要求找到一个字符串中最长的回文子串。回文是一种正读和反读都相同的字符串,例如 “madam” 或 “racecar”。

问题描述

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。示例:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

解题思路

解决这个问题有几种不同的方法,包括暴力法、动态规划、中心扩散法和Manacher算法。在这里,我们主要介绍中心扩散法和Manacher算法,因为它们在实际应用中更为高效。

中心扩散法

中心扩散法的核心思想是:对于字符串中的每个字符,尝试将其作为回文串的中心,向两边扩散,查找最长的回文串。

实现步骤:

  • 遍历字符串的每个字符,将每个字符作为回文中心。
  • 对于每个中心,向两边扩展,直到不再形成回文。
  • 记录并更新最长回文子串的长度和起始位置。
  • 考虑奇数长度和偶数长度的回文,分别处理。

代码示例

def longestPalindrome(s: str) -> str:if not s or len(s) < 1:return ""# 初始化最长回文子串的起始和结束索引start, end = 0, 0for i in range(len(s)):# 以 s[i] 为中心的最长回文子串的长度len1 = expandAroundCenter(s, i, i)# 以 s[i] 和 s[i+1] 为中心的最长回文子串的长度len2 = expandAroundCenter(s, i, i + 1)# 两种情况中的较大值maxLen = max(len1, len2)if maxLen > end - start:start = i - (maxLen - 1) // 2end = i + maxLen // 2return s[start:end + 1]def expandAroundCenter(s: str, left: int, right: int) -> int:# 从中心开始向两边扩散while left >= 0 and right < len(s) and s[left] == s[right]:left -= 1right += 1# 返回以当前中心扩散的回文子串的长度return right - left - 1# 测试代码
print(longestPalindrome("babad"))  # 输出: "bab" 或 "aba"
print(longestPalindrome("cbbd"))   # 输出: "bb"

代码解读

  • 函数 longestPalindrome:
    • 遍历字符串,对每个字符尝试两种情况的中心扩散:一种是该字符自身作为中心,另一种是该字符和其右邻字符共同作为中心(处理偶数长度的回文)。
    • 使用 expandAroundCenter 函数来实现中心扩散,并返回以当前中心可以扩散到的最长回文子串的长度。
    • 根据返回的长度和当前遍历的字符位置,更新最长回文子串的起始和结束位置。
  • 函数 expandAroundCenter:
    • 接收字符串和两个索引(代表当前考虑的中心)作为参数。
    • 从中心开始,向两边扩散,直到不能形成回文为止。
    • 返回扩散后回文的长度。

特点

中心扩散法的时间复杂度为O(n^2) ,其中n 是字符串的长度。空间复杂度为 O(1),因为除了输入字符串外,只需要常数级别的额外空间。

尽管在最坏情况下时间复杂度较高,中心扩散法因其实现简单、直观易懂而广受欢迎,特别适合在面试中快速解答。对于实际应用中的字符串长度不是特别大时,这种方法通常已经足够高效。

Manacher算法

Manacher 算法是一种高效的寻找字符串中最长回文子串的算法,时间复杂度为 (O(n))。其主要思想是通过构建一个辅助数组来记录每个字符作为回文中心时最大的回文半径,利用这些信息来避免重复的比较。

代码示例

下面是 Manacher 算法的 Python 实现:

def longestPalindrome(s: str) -> str:# 对原始字符串进行预处理t = '#'.join(f"^{s}$")n = len(t)p = [0] * ncenter = right = 0max_len = max_center = 0for i in range(1, n-1):# 利用已知的回文半径避免不必要的比较if i < right:p[i] = min(right - i, p[2*center - i])# 尝试扩展回文,更新p[i]while t[i + p[i] + 1] == t[i - p[i] - 1]:p[i] += 1# 如果通过扩展发现更长的回文,则更新center和rightif i + p[i] > right:center, right = i, i + p[i]# 更新最长回文子串的中心和长度if p[i] > max_len:max_len = p[i]max_center = i# 根据最大回文半径和中心计算最长回文子串的起始位置和结束位置start = (max_center - max_len) // 2return s[start: start + max_len]# 测试代码
print(longestPalindrome("babad"))
print(longestPalindrome("cbbd"))

代码解读:

  • 预处理:为了统一处理奇数长度和偶数长度的回文,首先对原字符串进行预处理,每个字符间插入一个特殊字符(这里使用 #),同时在首尾添加特殊字符(这里使用 ^ 和 $)以避免边界检查
  • 回文半径数组:p[i] 表示以第 i 个字符为中心的最长回文子串的半径长度。算法的核心是利用回文的对称性质,通过已知的回文信息来避免重复比较。
  • 中心扩展:对于每个位置 i,尽量利用之前计算的 p 数组值来避免重复计算。如果 i 在当前找到的最长回文子串的右边界内,可以利用其对称点的 p 值作为初始值。然后尝试向外扩展,直到找到以 i 为中心的最长回文子串。
  • 更新最长回文子串信息:在扩展过程中,如果发现更长的回文子串,更新记录的最大回文长度和对应的中心位置。
  • 结果提取:最后,根据记录的最长回文子串中心和半径,计算原始字符串中最长回文子串的位置,并返回该子串。
    Manacher 算法的巧妙之处在于通过特殊的预处理和对称性质,将问题的时间复杂度优化到线性级别,非常适合处理大规模字符串中的最长回文子串查找问题。

总结

中心扩散法的常见坑

1.	边界条件处理:
•	在扩散过程中,容易忽略字符串的边界条件。例如,当左右指针移动超出字符串范围时,应停止扩散。
•	解决方法:在扩散前检查左右指针是否在字符串范围内。
2.	奇偶回文的处理:
•	中心扩散法需要分别处理奇数长度和偶数长度的回文子串。有时可能会忽略其中一种情况,从而导致结果不准确。
•	解决方法:确保对每个中心点,都尝试以其为中心的奇数长度和偶数长度回文扩散。
3.	更新最长回文子串时的索引计算:
•	在更新最长回文子串的起始和结束索引时,由于字符串索引的偏移量计算可能会出错。
•	解决方法:仔细检查并正确计算基于当前中心点的最长回文子串的起始和结束索引。

Manacher算法的常见坑

1.	字符串预处理:
•	Manacher算法的预处理步骤是在字符串的每个字符间插入一个特殊字符(通常是一个不会在原字符串中出现的字符),以及在首尾添加不同的特殊字符。这一步骤容易出错,特别是在处理首尾字符时。
•	解决方法:仔细检查预处理步骤,确保正确地添加了特殊字符。
2.	回文半径数组的初始化和更新:
•	在实现Manacher算法时,正确初始化和更新回文半径数组 p 是关键。错误地初始化或更新 p 会导致错误的结果。
•	解决方法:明确理解 p 数组的含义,并确保在算法的每一步中都正确更新它。
3.	中心移动和边界更新:
•	算法的核心是维护一个当前最长回文的右边界和对应的中心点。在更新这两个变量时,容易出错。
•	解决方法:仔细检查每次扩散后是否需要更新当前最长回文的右边界和中心点。

中心扩散法和Manacher算法都是解决“最长回文子串”问题的有效方法。然而,无论是哪种方法,在实现时都需要小心处理边界条件、索引计算和特殊情况。熟悉这些坑并学会如何避免,可以帮助编程者写出更加准确和高效的代码。

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

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

相关文章

处理SAP报错:消息GLT2076 没有项目种类分配到科目 1481010102/1000

财务新建了个科目入账时报错&#xff1a;没有项目种类分配到科目。 查了下原因。原来是我们公司实施时启用了凭证分割功能。其中有个配置是这样的&#xff1a;给总账科目分类&#xff1a;IMG-财务会计&#xff08;新&#xff09;-总账会计核算-业务交易-凭证分解-为文档拆分给总…

如何理解Java中的cas

CAS&#xff0c;即 Compare and Swap&#xff0c;是一种并发编程中常用的原子操作&#xff0c;用于实现多线程环境下的同步。CAS 操作包括三个参数&#xff1a;内存位置&#xff08;通常是一个变量的内存地址&#xff09;、期望值和新值。操作的含义是&#xff1a;当且仅当内存…

20240322-1-协同过滤面试题

协同过滤面试题 1. 协同过滤推荐有哪些类型 基于用户(user-based)的协同过滤 基于用户(user-based)的协同过滤主要考虑的是用户和用户之间的相似度&#xff0c;只要找出相似用户喜欢的物品&#xff0c;并预测目标用户对对应物品的评分&#xff0c;就可以找到评分最高的若干个物…

IP代理池是什么?怎样判断IP池优劣?

许多做跨境电商的朋友们都会使用到IP代理池这个模块&#xff0c;那会有新想加入到跨境电商这个行业的朋友们会有疑问&#xff0c;IP代理池究竟是什么&#xff1f;今天为你解答。 IP代理池是一种集成多个代理IP的系统&#xff0c;其核心功能在于收集并维护大量的可用IP地址&…

大语言模型开发各个阶段的评估方法(未完)

大语言模型开发过程评估 1. 提出问题2. 大语言模型开发过程评估数据评估方法训练数据质量评估评价数据集或者基准的质量评估 模型评估方法评估基座模型评估通用大语言模型评估专用大语言模型 1. 提出问题 场景&#xff1a;我们要设计一个专有领域的大语言模型&#xff0c;设计…

什么是ECC?ECC 和 RSA 之间有何区别?

椭圆曲线密码学 (ECC) 是一种基于椭圆曲线数学的公开密钥加密算法。 它提供了一种执行密钥交换、数字签名和加密等加密操作的安全方式。 ECC 为 1977 年首次发布的 Rivest-Shamir-Adleman (RSA) 加密算法提供了一种替代性方案。 继续阅读&#xff0c;进一步了解椭圆曲线密码学…

CSC博士联培申请时间线

暂时只记得这么多了&#xff0c;有问题会及时修改。 #mermaid-svg-ZMjY9etaS7StCVuw {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ZMjY9etaS7StCVuw .error-icon{fill:#552222;}#mermaid-svg-ZMjY9etaS7StCVuw .e…

基于UDP的可靠传输协议QUIC协议

基于 UDP 协议实现的可靠传输协议的成熟方案了&#xff0c;那就是 QUIC 协议&#xff0c;已经应用在了 HTTP/3。 QUIC是如何实现可靠传输的 基于 UDP 协议实现的可靠传输协议的成熟方案了&#xff0c;那就是 QUIC 协议&#xff0c;已经应用在了 HTTP/3。 Packet header Packe…

采用大语言模型进行查询重写——Query Rewriting via Large Language Models

文章&#xff1a;Query Rewriting via Large Language Models&#xff0c;https://arxiv.org/abs/2403.09060 摘要 查询重写是在将查询传递给查询优化器之前处理编写不良的查询的最有效技术之一。 手动重写不可扩展&#xff0c;因为它容易出错并且需要深厚的专业知识。 类似地…

常识四堆外内存

常识四堆外内存-腾讯云开发者社区-腾讯云

跳跳!

题源 贪心~ 题目描述 你是一只小跳蛙&#xff0c;你特别擅长在各种地方跳来跳去。 这一天&#xff0c;你和朋友小 F 一起出去玩耍的时候&#xff0c;遇到了一堆高矮不同的石头&#xff0c;其中第 i 块的石头高度为hi​&#xff0c;地面的高度是 h0​0。你估计着&#xff0c;从第…

Monaco Editor系列(二)Hello World 初体验

前言&#xff1a;上一篇文章我主要分享了从 Monaco Editor 入口文件以及官方提供的示例项目入手&#xff0c;对一部分源码进行剖析&#xff0c;以及分享了初始化阶段代码的大致执行步骤&#xff0c;这一篇了来讲一下我们要用 Monaco Editor 的时候该怎么用。其中会涉及到一些 A…

ubuntu20.04 运行 lio-sam 流程记录

ubuntu20.04 运行 lio-sam 一、安装和编译1.1、安装 ROS11.2、安装 gtsam1.3、安装依赖1.4、下载源码1.5、修改文件1.6、编译和运行 二、官方数据集的运行2.1、casual_walk_2.bag2.2、outdoor.bag、west.bag2.3、park.bag 三、一些比较好的参考链接 记录流程&#xff0c;方便自…

选数(dfs,isprime)

题目&#xff1a;P1036 [NOIP2002 普及组] 选数 - 洛谷 | 计算机科学教育新生态 (luogu.com​​​​​​.cn) #include<bits/stdc.h> using namespace std; int n,k; int a[22]; long long ans; bool isprime(int n){for(int i2;i<sqrt(n);i){if(n%i0) return false;…

dm8 开启归档模式

dm8 开启归档模式 1 命令行 [dmdbatest1 dm8]$ disql sysdba/Dameng123localhost:5237服务器[localhost:5237]:处于普通打开状态 登录使用时间 : 3.198(ms) disql V8 SQL> select name,status$,arch_mode from v$database;行号 NAME STATUS$ ARCH_MODE ----------…

【嵌入式开发 Linux 常用命令系列 7.4 -- awk 处理文件名,去除后缀只保留文件名】

请阅读【嵌入式开发学习必备专栏 】 文章目录 awk 处理文件名&#xff0c;去除后缀只保留文件名 awk 处理文件名&#xff0c;去除后缀只保留文件名 在 shell 中&#xff0c; 可以使用 awk 来处理文件名&#xff0c;去除其后缀。下面是一个示例命令&#xff0c;它会将带有后缀的…

qtcreator配置msvc编译器 visual studio配置qt开发 以及使用对比

qtcreator配置msvc编译器开发 qtcreator在线安装&#xff08;qt5.12之后&#xff09;时候&#xff0c;默认选择的是mingw&#xff08;gcc编译器的windows版本&#xff09;的qt库以及migw编译器&#xff0c;我们可以额外勾选msvc&#xff08;visual studio的编译器&#xff0c;…

IPv4子网判断

有时候&#xff0c;服务后端需要对客户端的所属组进行判断&#xff0c;以决定何种访问策略权限。而客户端IP所在子网是一种很简单易实现的分组方法。 虽然现在早已经进入IPv6时代&#xff0c;不过IPv4在局域网仍广泛使用&#xff0c;它的定义规则相对简单&#xff0c;本文介绍的…

Python中输出显示台的设置

效果: 前言 这种文字显示的方式很适合新手来学习,毕竟新手还学不到pygame做游戏的, Python入门我们一般都学的是输入输出的游戏,但是如果加上一些文字和背景的改善可能会更好. 如何改变字体颜色 字体颜色(跟他的变量名是一样的): #改变字体颜色 RED \033[91m GREEN \033…

前端开发语言概览

前端开发语言概览 在当今数字化时代&#xff0c;前端开发已成为构建网站和应用程序不可或缺的一部分。前端开发主要关注用户界面的设计和交互效果&#xff0c;为用户提供良好的用户体验。而要实现这一目标&#xff0c;前端开发者需要掌握多种编程语言和技术。本文将详细介绍一些…