【Python 千题 —— 算法篇】寻找最长回文子串

请添加图片描述

Python 千题持续更新中 ……
脑图地址 👉:⭐https://twilight-fanyi.gitee.io/mind-map/Python千题.html⭐

字符串处理

题目背景

回文串是指一个字符串从左到右和从右到左读都是一样的。寻找一个字符串中的最长回文子串是许多经典算法问题之一,广泛应用于文本处理、数据分析和计算生物学等领域。

本题的挑战在于如何高效地找出最长的回文子串。在暴力搜索可能导致时间复杂度过高的情况下,掌握优化算法不仅可以提升代码性能,还能加深我们对字符串处理的理解。

题目描述

给定一个字符串 s,请你找出其中最长的回文子串。你可以假设 s 的最大长度为 1000。

输入描述

  • 一个字符串 s,长度在 [1, 1000] 之间,且字符为小写字母。

输出描述

  • 一个字符串,表示输入字符串中最长的回文子串。

示例

示例 ①

输入:

# 调用 longestPalindrome() 函数
print(longestPalindrome("babad"))

输出:

"bab"

解释:回文子串有 “bab” 和 “aba”,长度均为 3,返回其中一个即可。

示例 ②

输入:

print(longestPalindrome("cbbd"))

输出:

"bb"

解释:最长回文子串是 “bb”。


代码讲解与多种解法

解法一:暴力搜索法

最直接的解法是使用暴力搜索法,检查每一个子串是否为回文,并在检查时记录最长的回文子串。虽然该方法简单易懂,但它的时间复杂度为 O(n^3),对于较长的字符串来说效率较低。

def longestPalindrome(s):
    def is_palindrome(substring):
        return substring == substring[::-1]

    n = len(s)
    max_len = 0
    start = 0

    for i in range(n):
        for j in range(i, n):
            if is_palindrome(s[i:j+1]) and (j - i + 1) > max_len:
                max_len = j - i + 1
                start = i

    return s[start:start + max_len]

优点:

  • 实现简单直观,易于理解。

缺点:

  • 时间复杂度为 O(n^3),对于长字符串性能较差。

解法二:中心扩展法

中心扩展法通过从字符串的每个位置向外扩展,寻找回文子串。这种方法利用回文串的对称性,能在 O(n^2) 的时间复杂度内找到最长的回文子串,较暴力搜索法有明显的性能提升。

def longestPalindrome(s):
    if not s or len(s) == 1:
        return s

    def expand_around_center(left, right):
        while left >= 0 and right < len(s) and s[left] == s[right]:
            left -= 1
            right += 1
        return s[left + 1:right]

    max_palindrome = ""
    for i in range(len(s)):
        odd_palindrome = expand_around_center(i, i)
        even_palindrome = expand_around_center(i, i + 1)
        max_palindrome = max(odd_palindrome, even_palindrome, max_palindrome, key=len)

    return max_palindrome

优点:

  • 时间复杂度为 O(n^2),较为高效。
  • 代码较简洁,且适用于大多数实际场景。

缺点:

  • 对于极端大数据量,仍然可能存在性能瓶颈。

解法三:动态规划法

动态规划法通过构建一个二维表来记录子串是否为回文,以此减少重复计算的次数。其时间复杂度同样为 O(n^2),但在空间复杂度上会有额外的消耗 O(n^2),适用于需要明确记录所有回文状态的情况。

def longestPalindrome(s):
    n = len(s)
    if n == 0:
        return ""
    
    dp = [[False] * n for _ in range(n)]
    start, max_len = 0, 1
    
    for i in range(n):
        dp[i][i] = True
    
    for end in range(1, n):
        for start in range(end):
            if s[start] == s[end]:
                if end - start == 1 or dp[start + 1][end - 1]:
                    dp[start][end] = True
                    if end - start + 1 > max_len:
                        max_len = end - start + 1
                        longest_palindrome_start = start

    return s[longest_palindrome_start:longest_palindrome_start + max_len]

优点:

  • 可以记录所有子串的回文状态,便于追溯具体情况。
  • 理论上稳定的 O(n^2) 时间复杂度,适合分析数据时使用。

缺点:

  • 额外的 O(n^2) 空间复杂度,可能会导致空间使用过大。

解法四:马拉车算法

马拉车算法(Manacher’s Algorithm)是一种线性时间复杂度 O(n) 的算法。它利用回文的对称性,特别适合用于寻找最长回文子串。这是解决该问题的最优解,但其实现较为复杂。

def longestPalindrome(s):
    t = '#' + '#'.join(s) + '#'
    n = len(t)
    p = [0] * n
    c = r = 0
    max_center = 0
    
    for i in range(n):
        mirror = 2 * c - i
        if i < r:
            p[i] = min(r - i, p[mirror])
        
        while i + p[i] + 1 < n and i - p[i] - 1 >= 0 and t[i + p[i] + 1] == t[i - p[i] - 1]:
            p[i] += 1
        
        if i + p[i] > r:
            c, r = i, i + p[i]
        
        if p[i] > p[max_center]:
            max_center = i
    
    start = (max_center - p[max_center]) // 2
    return s[start:start + p[max_center]]

优点:

  • 时间复杂度为 O(n),是最优解,适用于需要极高效率的场景。
  • 对称性处理巧妙,可提升处理大数据集时的性能。

缺点:

  • 实现复杂度较高,理解和编码难度大。

总结与思考

寻找最长回文子串的方法多样,从暴力搜索到马拉车算法,每种方法都有其优缺点:

  1. 暴力搜索法:尽管简单直观,但效率较低,仅适合处理小规模数据。
  2. 中心扩展法:通过中心向外扩展,以较高效率找到回文子串,适用于大部分实际应用。
  3. 动态规划法:利用子问题记录状态,能有效避免重复计算,但空间复杂度较高。
  4. 马拉车算法:在时间复杂度上最优,适用于处理大规模数据的高效需求。

在实际应用中,选择合适的算法不仅依赖于问题的规模和复杂度,还需考虑实现的难易程度和应用场景。


扩展思考

  1. 文本处理中的应用:回文子串在自然语言处理、数据压缩等领域有广泛应用,理解回文结构有助于我们更好地处理文本数据。
  2. 字符串匹配算法:通过学习最长回文子串的求解方法,我们还能拓展到字符串匹配等更复杂的问题。
  3. 时间复杂度优化:马拉车算法为 O(n) 的复杂度,为我们提供了极致优化的思路,值得在其他复杂算法问题中学习和借鉴。

通过本文的讲解,相信你已经对寻找最长回文子串的各种算法有了深入的理解,并掌握了处理类似字符串问题的技巧。

关注博客,解锁更多字符串处理技巧!
作者信息

作者 : 繁依Fanyi
CSDN: https://techfanyi.blog.csdn.net
掘金:https://juejin.cn/user/4154386571867191

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用docker安装jenkins,然后使用jenkins本地发版和远程发版

使用docker安装jenkins&#xff0c;然后使用jenkins本地发版和远程发版 1、安装docker 1.安装必要的一些系统工具 sudo yum install docker-ce 2.添加软件源信息 sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 3.更新…

DAY74

#ifndef WIDGET_H #define WIDGET_H#include <QWidget>#include <QPainter> //画家类 #include <QTimer> //定时器类 #include <QTime> //时间类QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : …

风控——贷中管理介绍

一、概念介绍 贷中管理&#xff0c;指从贷款发放之日起&#xff0c;至贷款本息收回日期为止的贷款管理&#xff0c;贷中管理策略也集中在贷款发放后的管理和监控阶段&#xff0c;其目的是确保贷款资金的安全和有效使用&#xff0c;贷中预警和贷中调额在贷中管理中至关重要。 …

STMCuBeMX新建项目的两种匪夷所思的问题

错误一、保存地址名中有中文 错误&#xff1a;error1-haveCHinese_有中文\error1-haveCHinese_有中文.axf: error: L6002U: Could not open file error1-havechinese_???\stm32f1xx_it.o: No such file or directory 解决方法&#xff1a;重新导出&#xff0c;并且不要用中文…

Leetcode 701-二叉搜索树中的插入操作

给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和要插入树中的值 value &#xff0c;将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 &#xff0c;新值和原始二叉搜索树中的任意节点值都不同。 注意&#xff0c;可能存在多种有效的插入方式&a…

c# Avalonia 架构开发跨平台应用

Avalonia&#xff0c;读&#xff1a;阿瓦隆尼亚 由于以前的c#开发的windows平台项目想移植到信创平台&#xff08;UOS,Kylin)上&#xff0c;起初想用python重写&#xff0c;后来发现了这个Avalonia,用这个改动起来工作相对较少于是就先了解一下。 官网Avalonia Docs | Avalon…

贪心-单调递增的数字

给定一个非负整数 N&#xff0c;找出小于或等于 N 的最大的整数&#xff0c;同时这个整数需要满足其各个位数上的数字是单调递增。 &#xff08;当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单调递增的。&#xff09; 示例 1: 输入: …

如何显示Dialog窗口

文章目录 1. 概念介绍2. 使用方法2.1 Overlay效果2.1 Dialog效果 3. 示例代码4. 内容总结 我们在上一章回中介绍了"使用get显示snackBar"相关的内容&#xff0c;本章回中将介绍使用get显示Dialog.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在…

又一款强大好用的Shell脚本项目,支持Bash,Sh、Dash、Ksh等,甚至可以在编辑器中直接用,程序员必备!(附源码)

作为一个程序员&#xff0c;肯定经常都要和shell脚本打交道&#xff0c;Shell脚本可以帮我们自动化各种任务&#xff0c;但也经常有格式错误、拼写错误、逻辑错误等等麻烦&#xff0c;而且它不会告诉你错在哪里&#xff01; 今天就给大家分享一个超级实用的开源项目 - ShellCh…

Vue接入高德地图并实现基本的路线规划功能

目录 一、申请密钥 二、安装依赖 三、代码实现 四、运行截图 五、官方文档 一、申请密钥 登录高德开放平台&#xff0c;点击我的应用&#xff0c;先添加新应用&#xff0c;然后再添加Key。 如图所示填写对应的信息&#xff0c;系统就会自动生成。 二、安装依赖 npm i am…

Opencv中的直方图(3)直方图比较函数compareHist()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 比较两个直方图。 函数 cv::compareHist 使用指定的方法比较两个密集或两个稀疏直方图。 该函数返回 d ( H 1 , H 2 ) d(H_1, H_2) d(H1​,H2​…

el-form之表单校验自动定位到报错位置问题,,提升用户体验

需求描述 由于需要填写的表单项太多&#xff0c;提交的时候校验不通过&#xff0c;如果没填写的表单项在最上面&#xff0c;用户看不到不知道发生了啥&#xff0c;所以需要将页面滚动定位到第一个报错的表单项位置&#xff0c;提升用户体验 实现步骤 点击保存校验 报错项class会…

echarts 水平柱图 科技风

var category [{ name: "管控", value: 2500 }, { name: "集中式", value: 8000 }, { name: "纳管", value: 3000 }, { name: "纳管", value: 3000 }, { name: "纳管", value: 3000 } ]; // 类别 var total 10000; // 数据…

基于BiLSTM-CRF的医学命名实体识别研究(下)模型构建

一.生成映射字典 接下来需要将每个汉字、边界、拼音、偏旁部首等映射成向量。所以&#xff0c;我们首先需要来构造字典&#xff0c;统计多少个不同的字、边界、拼音、偏旁部首等&#xff0c;然后再构建模型将不同的汉字、拼音等映射成不同的向量。 在prepare_data.py中自定义…

Vue 获取参数

Vue 获取参数 在Vue.js开发过程中&#xff0c;获取参数是处理用户输入和动态数据的关键环节。本文将深度解析Vue中获取参数的几种方法&#xff0c;并分享一些扩展与高级技巧&#xff0c;帮助你更高效地完成参数处理任务。 文章目录 Vue 获取参数 一、Vue获取参数包含哪些几种1.…

【无标题】nginx服务器代码信息、数据库连接信息、敏感文件的路径、服务器版本信息发起有针对性的攻击

Nginx敏感文件的路径、服务器版本信息 Nginx 403、404、500等错误时&#xff0c;返回详细错误信息。报错信息中可能会包含服务器代码信息、数据库连接信息、敏感文件的路径、服务器版本信息等&#xff0c;攻击者可以利用这些信息来寻找已知的漏洞&#xff0c;从而发起有针对性…

mybatis 查询Not Found TableInfoCache

近期在工程迁移中遇到一个mybatis查询的问题&#xff0c;检查代码没有问题&#xff0c;但是报Not Found TableInfoCache 解决过程 是不是数据库对应表错误或者实体类指定的表名错误 查看配置文件链接的数据源是否正确TableName中指定的表名然后去数据库看一下是否存在 如果…

spring揭秘19-spring事务01-事务抽象

文章目录 【README】【1】事务基本元素【1.1】事务分类 【2】java事务管理【2.1】基于java的局部事务管理【2.2】基于java的分布式事务管理【2.2.1】基于JTA的分布式事务管理【2.2.2】基于JCA的分布式事务管理 【2.3】java事务管理的问题 【3】spring事务抽象概述【3.1】spring…

MSSQL数据库安全配置

预备知识 1、数据库安全的概念 对任何企业组织来说,数据的安全性最为重要。安全性主要是指允许那些具有相应的数据访问权限的用户能够登录到数据库,并访问数据以及对数据库对象实施各种权限范围内的操作,但是要拒绝所有的非授权用户的非法操作。因此安全性管理与用户管理是…

pptpd配置文件/etc/pptpd.conf详解

正文共&#xff1a;1111 字 2 图&#xff0c;预估阅读时间&#xff1a;1 分钟 如果要在Linux系统配置PPTP&#xff08;Point-to-Point Tunneling Protocol&#xff0c;点到点隧道协议&#xff09;VPN&#xff0c;一般是使用pptpd软件。pptpd命令通常从配置文件/etc/pptpd.conf中…