【LeetCode热题100】打卡第5天:最长回文子串

news2025/1/10 23:30:01

文章目录

  • 最长回文子串
    • ⛅前言
    • 🔒题目
    • 🔑题解

最长回文子串

⛅前言

大家好,我是知识汲取者,欢迎来到我的LeetCode热题100刷题专栏!

精选 100 道力扣(LeetCode)上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,熟练掌握这 100 道题,你就已经具备了在代码世界通行的基本能力。在此专栏中,我们将会涵盖各种类型的算法题目,包括但不限于数组、链表、树、字典树、图、排序、搜索、动态规划等等,并会提供详细的解题思路以及Java代码实现。如果你也想刷题,不断提升自己,就请加入我们吧!QQ群号:827302436。我们共同监督打卡,一起学习,一起进步。

博客主页💖:知识汲取者的博客

LeetCode热题100专栏🚀:LeetCode热题100

Gitee地址📁:知识汲取者 (aghp) - Gitee.com

Github地址📁:Chinafrfq · GitHub

题目来源📢:LeetCode 热题 100 - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台

PS:作者水平有限,如有错误或描述不当的地方,恳请及时告诉作者,作者将不胜感激

🔒题目

原题链接:5. 最长回文子串 - 力扣(LeetCode)

在这里插入图片描述

🔑题解

  • 解法一:暴力枚举

    这个方法简单、粗暴,但是想通过显然是想多了🤣LeetCode还没有这么水

    解题思路很简单,这里也就不展开来讲了,主要是对字符串所有可能出现的子串进行一个判断,然后得到最大子串。

    我这段代码有一个小注意点,那就是二层遍历要取等,因为substring方法是包前不包后的,如果不取等,当s的长度为2时,比如“aa”,最终的结果仍会是a,而不是aa,因为不取等压根就无法截取到第二个a

    /**
     * @author ghp
     * @title 最长回文子串
     */
    class Solution {
        public String longestPalindrome(String s) {
            if (s.length() == 1){
                return s;
            }
            int max = Integer.MIN_VALUE; // 记录当前最大回文子串的长度
            String result = null; // 记录最大回文子串
            // 遍历所有子串
            for (int i = 0; i < s.length(); i++) {
                for (int j = i + 1; j <= s.length(); j++) {
                    String target = s.substring(i, j);
                    // 判断是否是当前最大回文串
                    if (isPalindrome(target) && target.length() > max) {
                        max = target.length();
                        result = target;
                    }
                }
            }
            return result;
        }
    
        /**
         * 判断是否是回文字符串
         * @param target
         * @return true-是 false-否
         */
        private boolean isPalindrome(String target) {
            StringBuilder sb = new StringBuilder(target);
            String reverse = sb.reverse().toString();
            return reverse.equals(target);
        }
    }
    

    复杂度分析:

    • 时间复杂度: O ( n 3 ) O(n^3) O(n3)
    • 空间复杂度: O ( 1 ) O(1) O(1)

    其中 n n n 为字符串中字符的个数。之所以是 n 3 n^3 n3是因为reverse()的时间复杂度度是 O ( n ) O(n) O(n)

    在这里插入图片描述

  • 解法二:中心扩散算法(又学到一个新思想 o( ̄▽ ̄)ブ )

    主要思想:通过选取中心点,然后以中心点为根据地往两边扩散。

    实现步骤:

    • Step1:选取中心点。由于回文串存在单数与双数,所以中心点选取存在两种方式,如果是奇数中心点直接为单个字符,如果是偶数中心点直接为两个字符之间的间隔

      在这里插入图片描述

    • Step2:以中心点为根据地,往两边扩散。

    • Step3:遍历字符串所有的中心点。

    需要注意的点是计算回文串的长度,这里可能一下看不出规律,需要手动推导一下

    在这里插入图片描述

    /**
     * @author ghp
     * @title 最长回文子串
     */
    class Solution {
        public String longestPalindrome(String s) {
            if (s.length() == 1) {
                // 这里可以省略(后面判断兼顾了长度为1的情况),但是还是建议能早返回的尽量找点返回
                return s;
            }
            int start = 0; // 最长回文子串的起始索引
            int end = 0; // 最长回文子串的结束索引
            int len = 0;
            for (int i = 0; i < s.length(); i++) {
                // 回文子串长度为奇数时
                int len1 = centerSpread(s, i, i);
                // 回文子串长度为偶数时
                int len2 = centerSpread(s, i, i + 1);
                // 获取当前最大回文子串的长度
                len = len1 >= len2 ? len1 : len2;
                // 计算最大回文传的起点和终点(只有当最大回文串的长度发生变化时才需要重新计算)
                if (len > end - start) {
                    // 这里的计算公式,可以手动推导一下,有规律
                    start = i - (len - 1) / 2;
                    end = i + len / 2;
                }
            }
            return s.substring(start, end + 1);
        }
    
        /**
         * 中心扩散
         *
         * @param s
         * @param l 中心点左边界
         * @param r 中心点右边界
         * @return 中心扩散后能够形成的 最长回文子串的长度
         */
        private int centerSpread(String s, int l, int r) {
            while (l >= 0 && r <= s.length() && s.charAt(l) == s.charAt(r)) {
                l--;
                r++;
            }
            return r - l - 1;
        }
    }
    

    复杂度分析:

    • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
    • 空间复杂度: O ( 1 ) O(1) O(1)

    其中 n n n 为数组中元素的个数

  • 解法三:动态规划

    主要思路:我们可以直到回文串的规律,如果一个子串是回文串,那么往他前后在添加一个相同字符,它仍然是回文串。也就是说我们可以得到一个状态方程 P ( i , j ) = P ( i + 1 , j − 1 ) ∧ ( S i = = S j ) P(i,j)=P(i+1,j−1)∧(Si==Sj) P(i,j)=P(i+1,j1)(Si==Sj),因此我们可以从长度较短的回文串往长度较长的回文转进行一个状态转移,从而不断转换,最终得到最长回文子串

    public class Solution {
    
        public String longestPalindrome(String s) {
            int len = s.length();
            if (len < 2) {
                return s;
            }
    
            int maxLen = 1;
            int begin = 0;
            // dp[i][j] 表示 s[i..j] 是否是回文串
            boolean[][] dp = new boolean[len][len];
            // 初始化:所有长度为 1 的子串都是回文串
            for (int i = 0; i < len; i++) {
                dp[i][i] = true;
            }
    
            char[] charArray = s.toCharArray();
            // 递推开始
            // 先枚举子串长度
            for (int L = 2; L <= len; L++) {
                // 枚举左边界,左边界的上限设置可以宽松一些
                for (int i = 0; i < len; i++) {
                    // 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
                    int j = L + i - 1;
                    // 如果右边界越界,就可以退出当前循环
                    if (j >= len) {
                        break;
                    }
    
                    if (charArray[i] != charArray[j]) {
                        dp[i][j] = false;
                    } else {
                        if (j - i < 3) {
                            dp[i][j] = true;
                        } else {
                            dp[i][j] = dp[i + 1][j - 1];
                        }
                    }
    
                    // 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
                    if (dp[i][j] && j - i + 1 > maxLen) {
                        maxLen = j - i + 1;
                        begin = i;
                    }
                }
            }
            return s.substring(begin, begin + maxLen);
        }
    }
    
    作者:LeetCode-Solution
    链接:https://leetcode.cn/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    

    复杂度分析:

    • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
    • 空间复杂度: O ( n 2 ) O(n^2) O(n2)

    其中 n n n 为数组中元素的个数

  • 解法四:Manacher 算法

    这个算法可以说是回文串相关题目的最优算法了,时间复杂度直接降到了 O ( n ) O(n) O(n),但是实现起来是最复杂的,这里不做解释说明了,想了解的可以参考LeetCode官网

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

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

相关文章

部署OA系统

文章目录 前言一、OA系统基础1.OA系统2.魔方OA3.OA系统架构4.部署OA系统 二、使用步骤总结 前言 部署OA系统&#xff0c;以魔方OA为例 一、OA系统基础 1.OA系统 办公自动化&#xff08;Office Automation&#xff0c;简称OA&#xff09;&#xff0c;是将计算机、通信等现代化…

⑥电子产品拆解分析-食物电子秤

⑥电子产品拆解分析-食物电子秤 一、功能介绍二、电路分析以及器件作用三、原理图复现与学习1、电源电路2、按键电路3、其它接口电路 一、功能介绍 ①高精度0.1g称重&#xff1b;②内置锂电池和外加2个7号电池超长续航&#xff1b;③可进行克和盎司单位称重&#xff1b;④一键智…

Flask or FastAPI? Python服务端初体验

1. 引言 最近由于工作需要&#xff0c;又去了解了一下简单的python服务搭建的相关工作&#xff0c;主要是为了自己开发的模型或者工具给同组的人使用。之前介绍的针对于数据科学研究比较友好的一个可以展示的前端框架Streamlit可以说是一个利器。不过&#xff0c;随着ChatGPT的…

由前序和中序创建二叉树

算法分析 首先&#xff0c;前序是按照 根 -> 左子树 -> 右子树 这样的顺序来进行访问的&#xff0c;也就是说&#xff0c;前序给出的顺序一定是先给出根结点的&#xff0c;那么我们就可以根据前序的顺序来依次递归判断出每个子树的根结点了。 如下所示&#xff1a; 我…

源码角度分析多线程并发情况下数据异常回滚方案

一、 多线程并发情况下数据异常回滚解决方案 在需要多个没有前后顺序的数据操作情况下&#xff0c;一般我们可以选择使用并发的形式去操作&#xff0c;以提高处理的速度&#xff0c;但并发情况下&#xff0c;我们使用 Transactional 还能解决事务回滚问题吗。 例如有下面表结…

Go语言并发

Go语言并发学习目标 出色的并发性是Go语言的特色之一 • 理解并发与并行• 理解进程和线程• 掌握Go语言中的Goroutine和channel• 掌握select分支语句• 掌握sync包的应用 并发与并行 并发与并行的概念这里不再赘述, 可以看看之前java版写的并发实践; 进程和线程 程序、进程…

C语言3:根据身份证号输出生年月日和性别

18位身份证号码第7到10位为出生年份(四位数)&#xff0c;第11到12位为出生月份&#xff0c;第13 到14位代表出生日期&#xff0c;第17位代表性别&#xff0c;奇数为男&#xff0c;偶数为女。 用户输入一个合法的身份证号&#xff0c;请输出用户的出生年月日和性别。(不要求较验…

Java数据结构之第十三章、字符串常量池

目录 一、创建对象的思考 二、字符串常量池(StringTable) 三、再谈String对象创建 一、创建对象的思考 下面两种创建String对象的方式相同吗&#xff1f; public static void main(String[] args) {String s1 "hello";String s2 "hello";String s3 …

C# | 线性回归算法的实现,只需采集少量数据点,即可拟合整个数据集

C#线性回归算法的实现 文章目录 C#线性回归算法的实现前言示例代码实现思路测试结果结束语 前言 什么是线性回归呢&#xff1f; 简单来说&#xff0c;线性回归是一种用于建立两个变量之间线性关系的统计方法。在我们的软件开发中&#xff0c;线性回归可以应用于数据分析、预测和…

每日一博 - 对称加密算法 vs 非对称加密算法

文章目录 概述一、对称加密算法常见的对称加密算法优点&#xff1a;缺点&#xff1a;Code 二、非对称加密算法常见的非对称加密算法优点&#xff1a;缺点&#xff1a;Code 概述 在信息安全领域中&#xff0c;加密算法是保护数据安全的重要手段。 加密算法可以分为多种类型&am…

【Linux】线程互斥 与同步

文章目录 1. 背景概念多个线程对全局变量做-- 操作 2. 证明全局变量做修改时&#xff0c;在多线程并发访问会出问题3. 锁的使用pthread_mutex_initpthread_metux_destroypthread_mutex_lock 与 pthread_mutex_unlock具体操作实现设置为全局锁 设置为局部锁 4. 互斥锁细节问题5.…

哈夫曼树(Huffman)【数据结构】

目录 ​编辑 一、基本概念 二、哈夫曼树的构造算法 三、哈夫曼编码 假如<60分的同学占5%&#xff0c;60到70分的占15%…… 这里的百分数就是权。 此时&#xff0c;效率最高&#xff08;判断次数最少&#xff09;的树就是哈夫曼树。 一、基本概念 权&#xff08;we…

Zabbix4.0 自动发现TCP端口并监控

java端口很多&#xff0c;每台机器上端口不固定&#xff0c;考虑给机器配置组不同的组挂载模版&#xff0c;相对繁琐。直接使用同一个脚本自动获取机器上java相关的端口&#xff0c;推送到zabbix-server。有服务端口挂了自动推送告警 一、zabbix-agent配置过程 1、用户自定义参…

Apache Doris :Rollup 物化视图

整理了一下目前开启虚拟机需要用到的程序, 包括MySQL,Hadoop,Linux, hive,Doris 3.5 Rollup ROLLUP 在多维分析中是“上卷”的意思&#xff0c;即将数据按某种指定的粒度进行进一步聚合。 1.求每个城市的每个用户的每天的总销售额 select user_id,city,date&#xff0c; sum(…

树的简单介绍

目录 树的概念 ​ 树的相关概念 树的表示 二叉树的概念 特殊的二叉树 二叉树的存储结构 总结 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#…

Diffie-Hellman密钥交换协议(Diffie-Hellman Key Exchange,简称DHKE)

文章目录 Diffie-Hellman密钥交换协议&#xff08;Diffie-Hellman Key Exchange&#xff0c;简称DHKE&#xff09;一、密码学相关的数学基础1. 素数&#xff08;质数&#xff09;2. 模运算3. 费马小定理4. 对数5. 离散对数6. 椭圆曲线常见椭圆曲线1. NIST系列曲线secp256k1 2. …

Django实现人脸识别登录

Django实现人脸识别登录 Demo示例下载 1、账号密码登录 2、人脸识别登录 3、注册 4、更改密码 5、示例网站 点我跳转 一、流程说明 1、注册页面:前端打开摄像头,拍照,点击确定后上传图像 2、后端获取到图像,先通过face_recognition第三方库识别是否能够获取到人脸特征…

开闭原则正确姿势, 使用AOP优雅的记录日志, 非常的哇塞

&#x1f473;我亲爱的各位大佬们好&#x1f618;&#x1f618;&#x1f618; ♨️本篇文章记录的为 JDK8 新特性 Stream API 进阶 相关内容&#xff0c;适合在学Java的小白,帮助新手快速上手,也适合复习中&#xff0c;面试中的大佬&#x1f649;&#x1f649;&#x1f649;。 …

使用腾讯云服务器快速搭建网站教程

已经有了腾讯云服务器如何搭建网站&#xff1f;腾讯云服务器网以腾讯云服务器&#xff0c;借助宝塔面板搭建Web环境&#xff0c;然后使用WordPress博客程序搭建网站&#xff0c;大致分为三步&#xff0c;首先购买腾讯云服务器&#xff0c;然后在腾讯云服务器上部署宝塔面板&…

Vue + Vite 构建 自己的ChartGPT 项目

前期回顾 两分钟学会 制作自己的浏览器 —— 并将 ChatGPT 接入_彩色之外的博客-CSDN博客自定义浏览器&#xff0c;并集合ChatGPT&#xff0c;源码已公开https://blog.csdn.net/m0_57904695/article/details/130467253?spm1001.2014.3001.5501 目录 效果图 代码步骤&am…