【LeetCode】5,最长回文子串。 难度等级:中等。解法很多,值得推敲。

news2024/11/23 14:50:31

文章目录

    • 一、题目
    • 二、我的解答:双指针从头开始遍历
      • 2.1 暴力循环:超出时间限制
      • 2.2 优化后的暴力循环:虽然没有超时,但效率很低
    • 三、双指针中心扩散法(从字符串中心开始遍历)
    • 四、动态规划法
      • 4.1 我的错误解答:正向遍历字符串
      • 4.2 正确解答:逆向遍历字符串
    • 五、判断回文子串的多种写法

【LeetCode】5,最长回文子串。 难度等级:中等。

一、题目

在这里插入图片描述

二、我的解答:双指针从头开始遍历

思路:采用双指针(双重for循环)列举所有的子串,判断其是否为回文串,保存最长的回文串。时间复杂度为 O(n3):双指针 O(n2),判断子串是否为回文串 O(n)

2.1 暴力循环:超出时间限制

直接暴力循环会超出时间限制,因为时间复杂度太高。但是代码是正确的:

class Solution:
    def judgePalindrome_(self,s:str)->bool:
        if len(s)==1:
            return True
        length=len(s)
        for i in range(0,length//2+1):
            if s[i]!=s[length-i-1]:
                return False
        return True

    def longestPalindrome(self, s: str) -> str:
        if len(s)<=1:
            return s
        
        # 判断s是否为单一元素字符串,如"aaaaaaaaaa"。若不使用该判断,会超出时间限制。
        if s==s[0]*len(s):
            return s

        # 记录下maxLen和相应的起始位置
        maxLen=1   
        startIndex=0

        # 双指针
        length=len(s)
        for i in range(0,length-1):
            subStr=s[i]
            for j in range(1,length-i):
                subStr+=s[i+j]
                if self.judgePalindrome_(subStr):
                    if len(subStr)>=maxLen:
                        maxLen=len(subStr)
                        startIndex=i
        return s[startIndex:startIndex+maxLen]

2.2 优化后的暴力循环:虽然没有超时,但效率很低

由于我们只需要找到最长的子串,所以2.1中的代码是可以优化的。我们只需要判断长度大于当前maxLen的子串是否为回文子串即可,因为长度小于maxLen的子串即使是回文子串,也不可能是最长的,所以不需要判断。

优化后的代码如下:

class Solution:
    def judgePalindrome_(self,s:str)->bool:
        if len(s)==1:
            return True
        length=len(s)
        for i in range(0,length//2+1):
            if s[i]!=s[length-i-1]:
                return False
        return True

    def longestPalindrome(self, s: str) -> str:
        if len(s)<=1:
            return s
        
        # 判断s是否为单一元素字符串,如"aaaaaaaaaa"。若不使用该判断,会超出时间限制。
        if s==s[0]*len(s):
            return s

        # 记录下maxLen和相应的起始位置
        maxLen=1   
        startIndex=0

        # 双指针
        length=len(s)
        for i in range(0,length-1):
            subStr=s[i]
            for j in range(1,length-i):
                subStr+=s[i+j]
                # 只判断长度大于 maxLen 的子串即可
                if len(subStr) > maxLen and self.judgePalindrome_(subStr):
                    if len(subStr)>=maxLen:
                        maxLen=len(subStr)
                        startIndex=i
        return s[startIndex:startIndex+maxLen]

执行结果:

执行用时:9136 ms, 在所有 Python3 提交中击败了 4.98% 的用户
内存消耗:16 MB, 在所有 Python3 提交中击败了 49.25% 的用户

执行结果惨不忍睹,其实试行用例再多一点也超时了。所以这道题用双指针是行不通的。

三、双指针中心扩散法(从字符串中心开始遍历)

利用回文子串的对称性,以每一个位置为中心,用left和right双指针向两侧扩散。时间复杂度为 O(n2)

代码:

class Solution:
    def expend_(self,s,left,right):
        length=len(s)
        while left>=0 and right<length and s[left]==s[right]:
            left-=1
            right+=1
        # while循环会导致 left-=1 和 right+=1 多执行一次
        return left+1, right-1

    def longestPalindrome(self, s: str) -> str:
        if len(s)<=1:
            return s
        if len(s)==2:
            if s[0]==s[1]:
                return s
            else:
                return s[0]

        length=len(s)
        begin=0
        end=0
        for i in range(length-1):
            # 以奇数长度中心开始扩展, 此时初始扩展中心为 left=right=i
            left1,right1=self.expend_(s,i,i)
            # 以偶数长度中心开始扩展, 此时初始扩展中心分别为 left=i,right=i+1
            left2,right2=self.expend_(s,i,i+1)

            if right1-left1>end-begin:
                begin=left1
                end=right1
            if right2-left2>end-begin:
                begin=left2
                end=right2
        return s[begin:end+1]  

关键思路:使用一个函数实现 奇数长度和偶数长度字符串的两种中心扩散情况。

执行结果:

执行用时:340 ms, 在所有 Python3 提交中击败了 89.70% 的用户
内存消耗:16.1 MB, 在所有 Python3 提交中击败了 45.40% 的用户

四、动态规划法

对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。所以本题涉及到重复计算,那么就可以提前把较短的子串是否为回文串的判断结果保存下来,判断更长的子串时就可以利用之前的结果,减少计算量。

4.1 我的错误解答:正向遍历字符串

下面是我写的答案,对于一个测试用例,其计算结果是错误的:

输入:"aaaaa"
输出:"aaaa"
预期结果:"aaaaa"

code:

class Solution:
    def longestPalindrome(self, s: str) -> str:
        if len(s)<=1:
            return s
        if len(s)==2:
            if s[0]==s[1]:
                return s
            else:
                return s[0]
        
        # 记录最长回文子串的长度和起始下标
        maxLen=1
        startIndex=0

        length=len(s)
        dp=[[False]*length for _ in range(length)]
        # dp[i][j]表示s[i:j+1]是否为回文串

        # 初始状态
        for i in range(length-1):
            dp[i][i]=True    # 单个字符 s[i:i+1]=s[i] 一定是回文串
            if s[i]==s[i+1]:
                dp[i][i+1]=True    # 判断长度为2的子串是否为回文串
                if maxLen<2:
                    maxLen=2
                    startIndex=i
        
        for i in range(length-2):
            for j in range(i+2,length):
                # 状态转移方程, 前提条件是 len(s[i:j+1])>2
                dp[i][j]=(dp[i+1][j-1]==True and s[i]==s[j])
                if dp[i][j]==True and j-i+1>maxLen:
                    maxLen=j-i+1
                    startIndex=i
        return s[startIndex:startIndex+maxLen]              

错误原因分析:

显然对于输入为 s=“aaaaa” 的字符串,最长子串为 dp[0][4]=s[0:4+1]=“aaaaa”

但程序计算 dp[0][4]=(dp[1][3]==True and s[1]==s[3]) 时,外层 i 的循环只循环了 i=0 ,i=1的情况还没有遍历到,所以 dp[1][3]=False,则程序执行结果是 dp[0][4]=False;但显然 dp[0][4]=True 才是正确的。

其根本原因是在顺序遍历字符串的情况下,遍历 i+1 时无法用到 i 的结果,遍历 i 时也无法用到 i +1 的结果,导致失去了动态规划法的意义。

4.2 正确解答:逆向遍历字符串

要想让更长的字符串利用到短字符串的计算结果,必须逆向遍历字符串。代码如下:

class Solution:
    def longestPalindrome(self, s: str) -> str:
        if len(s)<=1:
            return s
        if len(s)==2:
            if s[0]==s[1]:
                return s
            else:
                return s[0]
        
        # 记录最长回文子串的长度和起始下标
        maxLen=1
        startIndex=0

        length=len(s)
        dp=[[False]*length for _ in range(length)]
        # dp[i][j]表示s[i:j+1]是否为回文串

        # 初始状态
        for i in range(length-1):
            dp[i][i]=True    # 单个字符 s[i:i+1]=s[i] 一定是回文串
            if s[i]==s[i+1]:
                dp[i][i+1]=True    # 判断长度为2的子串是否为回文串
                if maxLen<2:
                    maxLen=2
                    startIndex=i
        
        # i 一定要逆向遍历
        for i in range(length-3,-1,-1):
            for j in range(i+2,length):
                # 状态转移方程, 前提条件是 len(s[i:j+1])>2
                dp[i][j]=(dp[i+1][j-1]==True and s[i]==s[j])
                if dp[i][j]==True and j-i+1>maxLen:
                    maxLen=j-i+1
                    startIndex=i
        return s[startIndex:startIndex+maxLen]              

五、判断回文子串的多种写法

方法一:使用 for 循环遍历一半长度的字符串。

这种写法需要考虑是否区分字符串长度是奇数还是偶数(其实不需要区分),写起来不方便。代码如下:

def judgePalindrome_(self,s:str)->bool:
    if len(s)==1:
        return True
    length=len(s)
    for i in range(0,length//2+1):
        if s[i]!=s[length-i-1]:
            return False
    return True

方法一:使用 left 和 right 的双指针,分别从头部和尾部开始遍历,直到两个指针汇合时停止循环。

这种写法简洁明了,写法简单,不需要额外思考是否需要区分字符串长度是奇数还是偶数。代码如下:

def judgePalindrome_(self,s:str)->bool:
    if len(s)==1:
          return True
 	left=0
    right=len(s)-1
    while left<right:
        if s[left]!=s[right]:
            return False
        left+=1
        right-=1
    return True

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

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

相关文章

HTML+CSS实训——Day06——发现页的用JavaScript修改

仓库链接:https://github.com/MengFanjun020906/HTML_SX 前言 昨天学习了javascript的一些知识点&#xff0c;今天要学习dom的操作了&#xff0c;也就是文档对象模型的操作。 dom操作 <body><div id"i1">这是一个div</div><script>// dom…

一次redis主从切换导致的数据丢失与陷入只读状态故障

背景 最近一组业务redis数据不断增长需要扩容内存&#xff0c;而扩容内存则需要重启云主机&#xff0c;在按计划扩容升级执行主从切换时意外发生了数据丢失与master进入只读状态的故障&#xff0c;这里记录分享一下。 业务redis高可用架构 该组业务redis使用的是一主一从&am…

Spring Boot 如何实现邮件发送

Spring Boot邮件发送 在现代的Web应用程序中&#xff0c;邮件通知已经成为了一项非常重要的功能。例如&#xff0c;在用户注册、密码重置、订单确认等方面&#xff0c;我们通常都会使用邮件来通知用户。在Spring Boot应用程序中&#xff0c;我们可以使用JavaMailSender来实现邮…

2022年长三角高校数学建模竞赛A题学在长三角解题全过程文档及程序

2022年长三角高校数学建模竞赛 A题 学在长三角 原题再现&#xff1a; 长三角高等教育规模和优质高等教育资源数量处于全国领先水平。从 2019年和 2013-2019 年的平均值来看&#xff0c;长三角地区人口数量在全国占比分别是 16.22&#xff05;和 16.10&#xff05;&#xff0c…

在Css上吃过的亏

一、前言 最近参加了公司的一个小程序的开发项目&#xff0c;虽然很简单&#xff0c;但是非常急三天就要交。本来就是实习生加上前端不熟练的我&#xff0c;最终在Css定位上吃了很大的亏。今天就来了解一下Css中的几个定位。 二、什么是定位 在Css中有一个position属性&…

技术干货 | ​Navicat 面向 PostgreSQL 查询超时的工具解决方案

早前&#xff0c;我们发表过一篇《PostgreSQL 与 Navicat &#xff1a;数据库的中坚力量》 &#xff0c;从产品的发展介绍了两者的渊源与共性&#xff0c;获得了许多童鞋的认可。而随着PostgreSQL 在国内热度愈发高涨&#xff0c;应用也愈发广泛。近期&#xff0c;我们收到许多…

Chirpstack服务器简介和搭建教程

LoRaWAN网络主要优势体现在低成本、广域连接和低功耗&#xff0c;同时具有较多的开源平台可供使用。使用Chirpstack服务器可以快速搭建本地LoRaWAN网络。本文重点介绍一下Chirpstack服务器是做什么的和Chirpstack服务器的安装教程&#xff1a; Chirpstack是一款多组件的、部署…

vue中 antdesginVue <a-image/>图片标签去掉蒙层(鼠标滑过)里面的“预览”二字 或者使用deep自定义样式不生效问题。

vue中 antdesginVue 图片标签去掉蒙层&#xff08;鼠标滑过&#xff09;里面的“预览”二字 或者使用deep自定义样式不生效问题。 看似去掉这两个字很简单&#xff0c; 其实搞了我一上午&#xff0c;是真的不好去掉呀&#xff0c;这里得吐槽下ant官方 。。。。什么deep呀都是不…

是面试官放水,还是公司实在是太缺人?这都没挂,字节跳动原来这么容易进...

字节是大企业&#xff0c;是不是很难进去啊&#xff1f;” “在字节跳动做软件测试&#xff0c;能得到很好的发展吗&#xff1f; 一进去就有12K&#xff0c;其实也没有想的那么难” 直到现在&#xff0c;心情都还是无比激动&#xff01; 本人211非科班&#xff0c;之前在华为和…

PostgreSQL 16 beta 重磅发布,OpenPie 再次引领中国贡献关键力量

PostgreSQL 一直被誉为全球最先进的开源关系数据库之一&#xff0c;在 DB-engines 排行榜上长期稳居前五。5 月 25 日&#xff0c;PostgreSQL 全球开发团队官方宣布&#xff0c;PostgreSQL 16 Beta 1 版本正式发布。 本次 PostgreSQL 新版本功能亮点众多&#xff0c;涉及多个模…

Docker环境java程序的时间设置

先上解决方案 java程序生成的时间、日志时间不对的解决方案&#xff1a; #在Dockerfile文件中加入以下两行代码&#xff0c;用于指定bild的镜像为东八区 ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezoneDoc…

生产检验配置和操作

1、概念 在SAP系统的生产过程中运行中间产品或成品的质量流程&#xff0c;例如每个班次的检查等&#xff0c;在生产订单发布时生成检验批&#xff0c;在系统中进行检验的检验类型为03&#xff0c;当有生产订单发布时&#xff0c;将在系统中自动创建检验批。 2、前台和后台配置…

【操作系统】03.内存管理

存储器的层级结构 程序的运行 现代操作系统使用的连接方式&#xff1a;运行时动态链接 对某些模块的链接推迟到程序执行时才进行 现代操作系统使用的装入方式&#xff1a;动态重定位 程序装入内存后&#xff0c;逻辑地址不会立即转换成物理地址&#xff0c;而是推迟到指令执行…

Energy-Based Learning for Scene Graph Generation

[2103.02221] Energy-Based Learning for Scene Graph Generation (arxiv.org) 目录 Abstarct 1 Introduction 2 Approach 2.1 Scene Graph Generation 2.2 Energy Based Modeling 2.3 Energy Models for Scene Graphs Generation 2.4 Energy Model Architectue 2.4.1…

PCB多层板为什么都是偶数层?奇数层不行吗?

PCB板有单面、双面和多层的&#xff0c;其中多层板的层数不限&#xff0c;目前已经有超过100层的PCB&#xff0c;而常见的多层PCB是四层和六层板。那为何大家会有“PCB多层板为什么都是偶数层&#xff1f;”这种疑问呢&#xff1f;相对来说&#xff0c;偶数层的PCB确实要多于奇…

朋友面试字节要求月薪25K,明显感觉他背了很多面试题...

最近有朋友去字节面试&#xff0c;面试前后进行了20天左右&#xff0c;包含4轮电话面试、1轮笔试、1轮主管视频面试、1轮hr视频面试。 据他所说&#xff0c;80%的人都会栽在第一轮面试&#xff0c;要不是他面试前做足准备&#xff0c;估计都坚持不完后面几轮面试。 其实&#…

Unity WebGL打包配置本地服务器

第一步打包 1&#xff09;、先对Player Setting进行设置 2&#xff09;、设置打包的窗口大小 3&#xff09;、遇到异常以及压缩格式 第一个启用异常&#xff0c;指用户指定在运行时意外的代码行为&#xff08;通常被认为错误&#xff09;如何被处理&#xff0c;有三个选项…

进程(四)

进程四 2.21 管程2.22 死锁的概念2.23 死锁的处理策略2.23.1 破坏四个条件2.23.2 动态策略: 避免死锁2.23.3 死锁的检测和解除 2.21 管程 本小计知识概览 为什么要引入管程 管程的定义和基本特征 管程是一种特殊的软件模块&#xff0c;有这些部分组成: 局部于管程的共享数据结…

javaWeb ssh微博系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh微博系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开 发。开发环境为TOMCAT7.0,Myecli…

智慧校园建设主要包括哪些方面的内容?

在当今数字化的时代&#xff0c;越来越多的学校开始实施智慧校园计划&#xff0c;旨在为学生和教师提供更加高效、便捷的学习和教学环境。 那么&#xff0c;究竟什么是智慧校园呢&#xff1f;智慧校园建设主要包括哪些方面的内容&#xff1f;这篇就来详细讲一讲&#xff01; …