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

news2024/11/16 13:44:40

请添加图片描述

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

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

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

相关文章

2024年9月最新界面:自己如何在电脑上注册新的Google谷歌账号,图文详解和关键点解析、常见问题

有一些朋友需要通过谷歌账号来工作、学习或娱乐&#xff08;例如很多游戏需要用谷歌账号来注册和使用&#xff09;&#xff0c;但是不知道如何注册谷歌账号&#xff0c;或者知道如何注册&#xff0c;但是对于一些步骤或者注意事项不太熟悉&#xff0c;导致注册不成功&#xff0…

什么是LED智能会议一体机?COB超微小间距LED会议一体机大势所趋

LED智能会议一体机&#xff0c;作为现代会议室革新的核心装备&#xff0c;正逐步颠覆传统会议模式的界限。它不仅仅是一台集成了高清显示、触控互动、音视频处理及远程协作等功能于一体的智能设备&#xff0c;更是推动会议效率与体验双重飞跃的关键力量。随着技术的不断进步&am…

【重学 MySQL】十八、逻辑运算符的使用

【重学 MySQL】十八、逻辑运算符的使用 AND运算符OR运算符NOT运算符异或运算符使用 XOR 关键字使用 BIT_XOR() 函数注意事项 注意事项 在MySQL中&#xff0c;逻辑运算符是构建复杂查询语句的重要工具&#xff0c;它们用于处理布尔类型的数据&#xff0c;进行逻辑判断和组合条件…

【Protobuf】初识protobuf以及详细安装教程

W...Y的主页 &#x1f60a; 代码仓库分享 &#x1f495; 目录 序列化概念 ProtoBuf是什么 ProtoBuf在window下的安装 下载ProtoBuf编译器 配置环境变量 ​编辑 检查是否配置成功 ​编辑 ProtoBuf在Linux下的安装 下载ProtoBuf 安装ProtoBuf 序列化概念 首先我们…

小白开发中遇到的问题和解决方案

小白开发中遇到的问题和解决方案 文章目录 小白开发中遇到的问题和解决方案问题一 问题一 问题&#xff1a;端口别占用可能开开启多个应用 解决方法–在cmd执行下方红框中的命令关闭所有应用

MyBatis-MappedStatement什么时候生成?QueryWrapper如何做到动态生成了SQL?

通过XML配置的MappedStatement 这部分MappedStatement主要是由MybatisXMLMapperBuilder进行解析&#xff0c;核心逻辑如下&#xff1a; 通过注解配置的MappedStatement 核心逻辑就在这个里面了&#xff1a; 继承BaseMapper的MappedStatement 我们看看这个类&#xff0c;里…

idea如何配置模板

配置生成代码指令模板 注&#xff1a;我们常用的有sout,main等指令 第一步打开设置面板 1)按如下操作 2&#xff09;或者CtrlAltS快捷键直接弹出 第二步找 Editor>LiveTemplates 如下图 第三步创建模板 步骤如下 1&#xff09;创建分组名字 2)分组名字 3&#xff09;创…

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

pycharm如何安装selenium

在pycharm中打开一个项目后,点击Setting(ALTCtrlS快捷键) 然后点击install package完成后点击关闭这个窗口,就可以在代码中使用selenium了 成功后出现如下界面 编写一段正常可以运行操作chorme浏览器的 from selenium import webdriver # 指定ChromeDriver的路径driver we…

关于 PC打开“我的电脑”后有一些快捷如腾讯视频、百度网盘、夸克网盘、迅雷等各种捷方式在磁盘驱动器上面统一删除 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/142029325 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

淘宝开放平台交易类API解析以及如何测试?

调用淘宝开放平台的订单接口&#xff0c;主要可以通过以下几种途径进行&#xff1a; 1. 直接使用淘宝开放平台提供的API接口 步骤概述&#xff1a; 注册淘宝开放平台账号&#xff1a;首先&#xff0c;你需要在淘宝开放平台注册一个开发者账号。创建应用&#xff1a;在注册并…

Unity3D 小案例 像素贪吃蛇 01 蛇的移动

Unity3D 小案例 像素贪吃蛇 第一期 蛇的移动 像素贪吃蛇 今天来简单制作一个小案例&#xff0c;经典的像素贪吃蛇。 准备 首先调整一下相机的设置&#xff0c;这里使用灰色的纯色背景&#xff0c;正交视图。 接着&#xff0c;创建一个正方形&#xff0c;保存为预制体&#…

位运算技巧总结

一、常见位运算操作 1、基础位运算 & 按位与 有0则0 | 按位或 有1则1 ^ 按位异或 相同为0 不同为1 2、确定数n的二进制位中第x位是0还是1 目的&#xff1a;是0返回0&#xff0c;是1返回1 (n >> x) & 1 思路&#xff1a;1除了第一位其他位都是0&a…

01初识FreeRTOS【前情回顾篇】

为什么要使用FreeRTOS&#xff1f; 裸机轮询无法避免两个函数相互影响的问题&#xff0c;例如我们使用单片机在进行裸机开发时&#xff0c;我们使用了Delay延时函数&#xff0c;这时我们无法再执行其他的功能代码&#xff0c;需要等延时时间结束再执行其他代码&#xff0c;而使…

通过域名无法访问不到网站,IP可正常访问(DNS污染)

一 DNS被污染 就在刚刚突然访问不到csdn&#xff0c;域名无法访问如下图&#xff1a; 确认DNS是否解析有问题 1 ping 域名 先ping一下域名&#xff0c;ping 域名后得到ip, ping通了如下图&#xff1a; 2 使用IP访问测试 通过ip再访问网站&#xff0c;ip可以正常访问如下图&…

nginx搭配gateway的集群配置

一、nginx在http里配置如下信息 upstream gateway-cluster {server 127.0.0.1:10001;server 127.0.0.1:10002;}server {listen 1000;server_name localhost;location ~/zzw_project/(.*) {proxy_pass http://gateway-cluster/$1;proxy_set_header Host $host; # 代理设…

延迟渲染路径

1. 延迟渲染路径处理光照的方式 延迟渲染路径对光照的数量没有任何限制&#xff0c;并且所有灯光都可以采用逐像素渲染。理论上来说&#xff0c;即 使场景中有成百上千个实时灯光&#xff0c;依然可以保持比较流畅的渲染帧率。它支持法线纹理、阴影等等效果的处理&#xff1b;…

【C++】STL容器详解【下】

目录 一、list容器 1.1 list基本概念 1.2 lsit构造函数 1.3 list数据元素插入和删除操作 1.4 list大小操作 1.5 list赋值操作 1.6 list数据的存取 1.7 list反转排序 二、set/multiset容器 2.1 set/multiset基本概念 2.2 set构造函数 2.3 set赋值操作 2.4 set大小操…

ChatGPT+Simple Mind Map生成思维导图:快速提升学习效率

一、告别杂乱笔记&#xff0c;一键生成清晰思维导图&#xff01; 最近开始学习网络安全&#xff0c;一头扎进了各种协议、漏洞、防御机制的海洋中。信息量巨大&#xff0c;知识点零散&#xff0c;让我很快便陷入了“知识焦虑”——笔记越记越多&#xff0c;却越来越混乱&#…

Django+Vue3前后端分离学习(二)(重写User类)

一、重写User类&#xff1a; 1、首先导入User类&#xff1a; from django.contrib.auth.models import User 2、然后点在User上&#xff0c;按住ctrl 点进去&#xff0c;发现 User类继承AbstractUser Ctrl点进去AbstractUser&#xff0c;然后将此方法全部复制到自己APP的mo…