【leetcode】第5题:最长回文子串

2023-05-16

目  录:

一、暴力解法

二、动态规划

三、中心扩展法

四、Manacher 算法


先说明几个概念:

1. 子串:小于等于原字符串长度,由原字符串中任意个连续字符组成的子序列;

2. 回文:关于中间字符对称的字符串,例如:"ababa"(单核)、"abccba"(双核);

3. 最长回文子串:回文子串中最长的子串。

一、暴力解法【时间复杂度:O(n^{3})】

  •  基本思路:遍历该字符串所有的子串,找出其中是回文子串且长度最长的那个。所以,我们可以倒着遍历该字符串,从最长的子串开始,这样只用找到第一个是回文字符串就可以了,它一定是原字符串最长的回文子串。

1、 从最长的子串开始,遍历该字符串的所有子串(时间复杂度为:O(n^2));

2、判断当前子串是否为回文串(时间复杂度为:O(n));

3、当前子串为回文时,则找到了原字符串的最长回文子串,结束遍历;否则,继续遍历,直到遍历完所有子串。

  • 代码实现
public class LongestPalindrome_5 {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        getLongestPalindrome1(str);
    }

    // 暴力解法
    public static String getLongestPalindrome1(String str){
        if(str.length() <= 1){
            return str;
        }

        // 前两层循环是求字符串的所有子串
        for(int i = str.length(); i > 0; i--){
            for(int j = 0; j <= str.length() - i; j++){
                String sub = str.substring(j, i + j);
                int count = 0;
                // 检验当前的子串是否为回文串
                for(int k = 0; k < sub.length() / 2; k++){
                    // k是从0开始的,所以是sub.length-k-1
                    if(sub.charAt(k) == sub.charAt(sub.length() - k - 1)){
                        count++;
                    }
                }
                if(count == sub.length() / 2){
                    System.out.println(sub);
                    return sub;
                }
            }
        }
        return "";  // 没有
    }
}
  • 从分析和代码实现上,可以很明显的看出,暴力解法的时间复杂度是:O(n^3),无论是笔试还是面试显然都是不行的。

二、动态规划【时间复杂度:O(n^{2})】

回文字符串的子串也是回文,比如P[i, j](表示以 i 开始,以 j 结束的子串)是回文字符串,那么P[i+1, j-1]也是回文字符串。这样最长回文子串就能分解成一系列子问题了。这样需要额外的空间O(N^2),算法复杂度也是O(N^2)。

  • 首先定义状态方程和转移方程:

P[i, j] = false:表示子串[i, j]不是回文串;P[i, j] = true:表示子串[i, j]是回文串。

P[i, i] = true:当且仅当P[i+1, j-1] = true && (s[i] == s[j])否则p[i,j] =false;

public class LongestPalindrome_5 {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        String subStr = getLongestPalindrome3(str);
        System.out.println(subStr);
    }

    // 动态规划
    public static String getLongestPalindrome2(String str){
        if(str == null && str.length() <= 0){
            return "";
        }

        int len = str.length();
        int start = 0;            // 记录字符串起始的位置
        int maxLength = 1;        // 记录回文串的最大长度
        boolean dp[][] = new boolean[str.length()][str.length()];

        // 长度为1和2的子串的初始化
        for(int i = 0; i < len; i++){
            // 初始化所有长度为1的子串
            dp[i][i] = true;
            // 初始化所有长度为2的子串
            if(i < len - 1 && str.charAt(i) == str.charAt(i + 1)){
                dp[i][i + 1] = true;
                start = i;
                maxLength = 2;
            }
        }

        // 以字符串长度为1和2的子串为基础,推导长度:3~len 的子串的dp
        for(int strlen = 3; strlen <= len; strlen++){
            // 从头开始,遍历长度为strlen的子串,并判断它们是否为回文串
            for(int i = 0; i <= len - strlen; i++){
                int j = i + strlen - 1;   // 子串结束位置的下标
                if(dp[i + 1][j - 1] && str.charAt(i) == str.charAt(j)){
                    dp[i][j] = true;
                    // 更新最大回文子串长度为当前子串长度,因为子串长度是不断增加的,所以最后一个回文串肯定是最长的
                    maxLength = strlen;
                    start = i;  // 记录回文串开始位置的下标
                }
            }
        }

        if(maxLength > 0){
            return str.substring(start, start + maxLength);
        }
        return "";
    }
}

三、中心扩展法【时间复杂度:O(n^{2})】

事实上,只需使用恒定的空间,我们就可以在 O(n^2) 的时间内解决这个问题。

我们观察到回文中心的两侧互为镜像。因此,回文可以从它的中心展开,并且只有 2n −1 个这样的中心。

你可能会问,为什么会是 2n - 1 个,而不是 n 个中心?原因在于所含字母数为偶数的回文的中心可以处于两字母之间(例如 {“abba”}的中心在两个{‘b’}之间)。【和在两个字符之间添加“#”是一个道理】

public class LongestPalindrome_5 {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        String subStr = getLongestPalindrome3(str);
        System.out.println(subStr);
    }

    // 中心扩展法
    public static String getLongestPalindrome3(String str){
        if(str == null && str.length() <= 0){
            return "";
        }

        int maxLength = 1;
        int start = 0;

        // 类似于aba这种情况,以i为中心向两边扩展
        for(int i = 0; i < str.length(); i++){
            int j = i - 1;
            int k = i + 1;
            while((j >= 0 && k < str.length()) && str.charAt(j) == str.charAt(k)){
                if(k - j + 1 > maxLength){
                    maxLength = k - j + 1;
                    start = j;
                }
                j--;
                k++;
            }
        }

        // 类似于abba这种情况,以i,i+1为中心向两边扩展
        for(int i = 0; i < str.length(); i++){
            int j = i;
            int k = i + 1;
            while((j >= 0 && k < str.length()) && str.charAt(j) == str.charAt(k)){
                if(k - j + 1 > maxLength){
                    maxLength = k - j + 1;
                    start = j;
                }
                j--;
                k++;
            }
        }
        if(maxLength > 0){
            return str.substring(start, start + maxLength);
        }
        return "";
    }
}
  • 可以看到上面代码非常长,可以发现主要就是奇回文和偶回文两种情况的处理,代码高度一致。可以精简下,这里贴出 leetcode 官方提供的代码。
  • 其实对于笔试来说,通过最重要,还是推荐上面的代码,虽然长,但是思路比较清晰。
public class LongestPalindrome_5 {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        String subStr = getLongestPalindrome4(str);
        System.out.println(subStr);
    }

    // 中心扩展法:精简版
    public static String getLongestPalindrome4(String str){
        if(str == null || str.length() < 1){
            return "";
        }
        int start = 0, end = 0;
        for(int i = 0; i < str.length(); i++){
            int len1 = expandAroundCenter(str, i, i);            // 偶数回文
            int len2 = expandAroundCenter(str, i, i + 1);  // 奇数回文
            int len = Math.max(len1,len2);
            if(len > end - start){
                start = i - (len - 1) / 2;
                end = i + len / 2;
            }
        }
        return str.substring(start, end + 1);
    }

    public static int expandAroundCenter(String str, int left, int right){
        while(left >= 0 && right < str.length() && str.charAt(left) == str.charAt(right)){
            left--;
            right++;
        }
        // 算的是左右两边的中间的长度
        return right - left - 1;
    }
}

四、Manacher 算法

后续补上.......

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【leetcode】第5题:最长回文子串 的相关文章

  • Vmware 虚拟机瘦身

    问题 vmware 占用硬盘空间只增大不减少 即使删除虚拟机系统里面的文件 xff0c 占用宿主机的硬盘空间也不释放 导致虚拟机越来越大 xff01 方法一 xff1a 运用虚拟机自带的磁盘整理工具来进行磁盘清理 xff01 1 虚拟机 g
  • 从peach源码生成工程文件

    编译过程中几个软件 msvc Microsoft Visual C 43 43 often abbreviated as MSVC or VC 43 43 is an integrated development environment I

随机推荐

  • QT读取GPS信息,信息组包,防止异常错乱

    以下如果有错误 xff0c 请留言指正 GNRMC为双模定位 xff1a GPRMC 43 BD 读取 GNRMC经纬度信息 xff1b 含GPRMC xff1b 处理类似 GNRMC 064401 65 A 3110 4706987 N
  • 自定义数据结构(C++)

    1 动态数组 include lt iostream gt template lt typename T gt class MyVector T m p int m capacity int m size public 构造函数 expli
  • ubuntu20 下 qtcreator ros配置过程

    1 去下载qtcreator ros bionic latest offline installer run文件进行安装 xff1b 参考这里 xff1a How to Install Users ROS Qt Creator Plug i
  • 【竞赛记录】kpi异常检测

    搞了个华为的KPI异常检测竞赛 xff0c 当然搞的时候就没觉得自己会拿奖 xff08 我指安慰奖 xff09 xff0c 但没想到有这么悬殊 一方面是没搞过时间序列的东西 xff0c 好多东西要重新开始学 xff1b 另一方面是 xff0
  • vscode调试container中的程序

    在写cmu14 445的project时 xff0c 我希望在本地vscode编辑代码 xff0c 然后在docker中编译和测试代码 但是如果测试出了问题 xff0c 直接在本地调试就变得麻烦了 所以希望利用vscode进行远程调试 参考
  • mc_pos_control.cpp 之 generate_attitude_setpoint(dt)

    span class hljs keyword void span MulticopterPositionControl generate attitude setpoint span class hljs keyword float sp
  • VM虚拟机Ubuntu 22.04 LVM磁盘扩容报错:GPT PMBR size mismatch (104857599 != 209715199) will be corrected by wri

    背景 xff1a 原本是50G的 xff0c 添加了50G磁盘 xff0c 但是系统显示报错如标题 1 虚拟机增加硬盘容量 2 查看ubuntu中当前硬盘信息 输入命令 df h 输入命令 fdisk l 出现报错 解决 xff1a GPT
  • Docker容器图形界面显示(运行GUI软件)的配置方法

    https hub docker com r dorowu ubuntu desktop lxde vnc https github com fcwu docker ubuntu vnc desktop docker ubuntu vnc
  • esp8266 硬件平台

    esp8266 硬件平台 概述对模组的选择最小系统 概述 首先8266是个芯片 好像有掉进某个巨坑 xff0c 哈哈 认识一下芯片出产是乐鑫 模组出产是安信可 一般都使用模组 xff0c 因为射频电路设计的门槛比较高 xff0c 不懂时候近
  • esp32s2 tinyusb vendor device小总结

    usb 802 11 wifi网卡 xff0c 遇到点问题 对tinyusb的架构有一点小了解了 发送路径 xff1a 用户调用tud vendor write urb msg urb len 启动传输 tud vendor write g
  • Java面试回报率最高的5本书!别再傻傻的看入门到放弃系列了!

    二八定律工欲善其事 xff0c 必先利其器读一本好书 如果你是一名 程序猿 xff0c 那么你肯定免不了准备各种面试 毕竟无论校招还是社招都是要经过严格的面试流程 xff0c 才能入职 可能每个人准备面试的方法也不一样 xff0c 但是读一
  • 2020互联网大厂硕士生薪资出炉!来源OfferShow爆料整理!

    今天和大家聊一聊 2020 届秋招硕士生开发岗位的薪资情况 最近看网上有人爆料 2020 互联网大厂校招硕士生的薪资情况 xff0c 这份榜单中包含了 10 家公司 xff0c 其中有 4 家是我秋招中拿到 offer 且谈过薪资的 榜单中
  • nvidia nx平台HDMIDP输出红色噪声调试记录

    1 前言 使用定制板 Jetpack版本是4 4 1 L4T 32 4 4 使用以下命令 当同时通过nvoverlaysink输出视频到HDMI DP时 在整个DP屏幕上出现红色噪声错误 gst launch 1 0 videotestsr
  • 没有实习我是不是就拿不到大厂offer了吗?---校招答疑

    可能是快放寒假了 xff0c 也可能是再有 2 3 个月就要进入 2020 年春招 xff08 应届生春季校招和暑期实习生招聘 xff09 了 越来越多的同学开始问实习的事情了 我认识的 20 届的同学有已经日常实习两个月以上的 xff0c
  • 最新42道计算机网络面试题!-- 附答案

    写在前面 计算机网络 计算机操作系统这两个 兄弟 是所有开发岗位都需要 结拜 的 xff0c 不管你是 Java C 43 43 还是测试 对于后端开发的童鞋来说 xff0c 计算机网络的重要性不亚于语言基础 xff0c 毕竟平时开发经常会
  • 秋招没拿到心仪offer,春招还有机会吗?该如何准备?

    最近很多秋招不理想或者考研不理想的同学问我这样一个问题 xff1a 互联网公司春招还有没有机会 xff1f 其实我相信大部分同学问这个问题的时候 xff0c 心里都是有答案的 xff0c 只不过想找一个他认为可以让他安心的人说出这个答案 那
  • 使用Filezilla Server软件配置FTP的全过程

    博主秋招提前批已拿百度 字节跳动 拼多多 顺丰等公司的offer xff0c 可加微信 xff1a pcwl Java 一起交流秋招面试经验 xff0c 可获得博主的秋招简历和复习笔记 使用Filezilla Server软件配置FTP的全
  • JAVA的四类八种基本数据类型

    先说明两个词汇的基本概念 xff1a bit xff08 位 xff09 xff1a 位是计算机中存储数据的最小单位 xff0c 指二进制数中的一个位数 xff0c 其值为 0 或 1 byte xff08 字节 xff09 xff1a 字
  • 集线器、交换机与路由器有什么区别?

    转发自 xff1a https mp weixin qq com s YXWBw3aFTSEFvkg oN9eQA 我相信我们都玩过一款特别火的游戏 xff1a 帝国时代 小时候想要玩帝国时代 xff0c 需要到软件城购买盗版光盘安装 xf
  • 【leetcode】第5题:最长回文子串

    目 录 一 暴力解法 二 动态规划 三 中心扩展法 四 Manacher 算法 先说明几个概念 xff1a 1 子串 xff1a 小于等于原字符串长度 xff0c 由原字符串中任意个连续 字符组成的子序列 xff1b 2 回文 xff1a