【LeetCode】5. 最长回文子串

题目链接


在这里插入图片描述
在这里插入图片描述

Python3

方法: 暴力求解 ⟮ O ( n 3 ) 、 O ( 1 ) ⟯ \lgroup O(n^3)、O(1)\rgroup O(n3)O(1)⟯

class Solution:
    def longestPalindrome(self, s: str) -> str:
        if s == s[::-1]:
            return s
        n = len(s)
        res = s[0]
        max_length = 1 # 至少一个字符
        for i in range(n-1): # 
            for j in range(i+1, n):
                if j - i + 1 > max_length and s[i:j+1] == s[i:j+1][::-1]: # s[i:i+1] 必然回文,直接跳过
                    res = s[i:j+1]
                    max_length = j - i + 1
                        

        return res

方法一: 动态规划 (回文串同时去掉头尾后 依然是回文串) ⟮ O ( n 2 ) ⟯ \lgroup O(n^2)\rgroup O(n2)⟯

在这里插入图片描述

class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        if s == s[::-1] or n <= 1:
            return s
        
        dp = [[False]*n for _ in range(n)]
        for i in range(n):
            dp[i][i] = True
        
        max_length = 1
        index_left = 0  # 维护 前后界下标 占用的空间 似乎 比 直接维护 字符串少些

        for right in range(1, n):
            for left in range(right):
                if s[left] == s[right]:
                    if right - left <= 2: ##  aba(right-left==2)  aa(right-left==1)
                        dp[left][right] = True 
                    else:  # 长度 大于 3或2, 取决于 同时去掉两端的字符串 为回文
                        dp[left][right] = dp[left+1][right-1]
                
                ## 处理好后,判断
                if right - left + 1 > max_length and dp[left][right]: # 当长度 够长 才 决定是否更新
                    max_length = right - left + 1  # 注意长度计算
                    index_left = left 
                
        return s[index_left : index_left + max_length] # 注意 转换

在这里插入图片描述

⭐ 方法二:中心扩展法 ⟮ O ( n 2 ) 、 O ( 1 ) ⟯ \lgroup O(n^2)、O(1)\rgroup O(n2)O(1)⟯

class Solution:
    def longestPalindrome(self, s: str) -> str:
        # 子模块 中心扩散
        def expandAroundCenter(s, left, right):
            while left >= 0 and right <= len(s)-1 and s[left] == s[right]:
                left -= 1
                right += 1

            return left+1, right-1  ## 返回 回文字符串 左右 下标    ab 01  


        # 主模块
        ## 处理特殊情况
        n = len(s)
        if s == s[::-1] or n <= 1:
            return s 
        
        max_length = 1
        index_left = 0
        for i in range(n):
            left1, right1 = expandAroundCenter(s, i, i)  ## 中心为一个字符
            left2, right2 = expandAroundCenter(s, i, i+1)  # 中心为 两个一样的字符
            if right1- left1 + 1 > max_length: 
                max_length = right1 - left1 + 1 
                index_left = left1 
            if right2 - left2 + 1 >  max_length:
                max_length = right2 - left2 + 1
                index_left  = left2  

        return s[index_left : index_left+max_length]


在这里插入图片描述

⭐ 方法三:Manacher(马拉车) 法 ⟮ O ( n ) ⟯ \lgroup O(n)\rgroup O(n)⟯ 【空间换时间】

在这里插入图片描述
在这里插入图片描述

写法一: 维护盒子左右两边
class Solution:
    #  子模块   中心扩散模块    盒外 以及 边界 仍需要扩展  
    def expandAroundCenter(self, s, left, right):
        while left >= 0 and right <= len(s)-1 and s[left] == s[right]:
            left -= 1
            right += 1

        ## 由于 边界是必定满足的,所以循环跳出 必定是 s[left] != s[right]
        # return s[left+1: right]  ### 注意 切片[] 是左合右开的
        return (right - left - 2) // 2  ## 注意这里要返回 回文半径 =[right - 1 - (left+1)] //2    
    # 主模块
    def longestPalindrome(self, s: str) -> str:
        """马拉车(统一处理奇偶回文串、进一步利用之前记录的对称关系)"""

        s = '#' + '#'.join(list(s)) + '#'  ## 插入特殊字符,s改造后 总长度为奇
        d = []   ## 记录 回文半径

        start, end = 0, -1   ## 用于 记录 最长回文串的起始和终止位置
        right = -1   ## 维护 盒子的 右端位置, 根据  回文串的特性, left = 2 * center - right
        left = 0   ## 维护盒子  左边 位置
        
        ## 写入 回文半径 d
        d.append(1)
        for i in range(1, len(s)):
            if i <= right: ## 位于 盒内 和边界
                mirror_left = left + right - i  ## 左边镜像的位置
                min_d = min(d[mirror_left], right-i)   ## 只扩展 盒子外的
                cur_d = self.expandAroundCenter(s, i - min_d, i + min_d)  ## 左右扩展
            else:
                cur_d = self.expandAroundCenter(s, i, i) ## 位于 盒外,无法利用之前的信息,直接左右扩展
            d.append(cur_d)

            if i + cur_d > right: ### 更新盒子 的左边界 和 右边界
                left =  i - cur_d 
                right = i + cur_d

            ## 更新  最长回文串的  位置
            if right - left > end - start:
                start = left
                end = right

        return s[start + 1 : end + 1 : 2]
写法二: 维护盒子 右侧 和 中心
class Solution:
    # 子模块
    def expandAroundCenter(self, s, left, right):
        while left >= 0 and right <= len(s)-1 and s[left] == s[right]:
            left -= 1
            right += 1

        return (right - left - 2) // 2  # 返回 回文半径

    # 主模块
    def longestPalindrome(self, s: str) -> str:
        # 改造 s ,统一成  奇数长度
        s = '#' + '#'.join(list(s)) + '#'

        d = []  # 记录回文半径

        start, end = 0, -1  ## 回文串 起始 和 结束 下标
        center = 0  # 盒子中心坐标
        right = -1 # 盒子 右侧下标

        d.append(1)
        for i in range(1, len(s)):
            if i <= right: 
                mirror_left = 2 * center - i
                min_d = min(d[mirror_left], right-i)
                cur_d = self.expandAroundCenter(s, i - min_d, i + min_d)
            else:
                cur_d = self.expandAroundCenter(s, i, i)
            d.append(cur_d)
            
            # 更新 盒子
            if i + cur_d > right:
                center = i 
                right = i + cur_d 

            # 更新 最长回文串 位置
            if 2 * cur_d + 1 > end - start:
                start = i - cur_d 
                end = i + cur_d 
        return s[start + 1 : end + 1 : 2]

在这里插入图片描述

C++

方法二:中心扩展法 ⟮ O ( n 2 ) 、 O ( 1 ) ⟯ \lgroup O(n^2)、O(1)\rgroup O(n2)O(1)⟯

class Solution {
public:
    // 子模块
    pair<int, int> expandAroundCenter(const string & s,int left, int right){
        while (left >= 0 && right <= s.size()-1 && s[left] == s[right]){
            --left;
            ++right;
        }
        return {left + 1, right - 1};
    }

    // 主模块
    string longestPalindrome(string s) {
        int start = 0, end = 0; // 当前 回文串 的起止下标
        for (int i = 0; i < s.size(); ++i){
            auto [left1, right1] = expandAroundCenter(s, i, i);
            auto [left2, right2] = expandAroundCenter(s, i, i+1);
            if (right1 - left1 > end - start){
                start = left1;
                end = right1;
            }
            if (right2 - left2 > end - start){
                start = left2;
                end = right2;
            }
        }
        return s.substr(start, end - start + 1);   // 注意写法
    }
};

方法三:Manacher(马拉车) 法 ⟮ O ( n ) ⟯ \lgroup O(n)\rgroup O(n)⟯ 【空间换时间】

写法一: 维护 盒子左右两侧下标
class Solution {
public:
    // 子模块
    int expandAroundCenter(const string &s, int left, int right){
        while (left >= 0 && right <= s.size()-1 && s[left] == s[right]){
            --left;
            ++right;
        }
        return (right - left - 2)/2;  // 返回  回文半径
    }

    // 主模块
    string longestPalindrome(string s){
        // 修改s  插入特殊字符
        string t = "#";  // 注意是字符串 形式
        for (char c : s){
            t += c;
            t += '#';
        }
        t += '#';
        s = t;

        int start = 0, end = -1;  // 维护 最长回文串的 起止下标
        int left = 0, right = -1;
        vector<int> d; 
        d.emplace_back(1);
        for (int i = 1; i < s.size(); ++i){
            int cur_d;
            if (i <= right){// 位于盒内 或 边界
                int mirror_left = left + right - i;
                int min_d = min(d[mirror_left], right - i);
                cur_d = expandAroundCenter(s, i - min_d, i + min_d);
            }
            else{
                cur_d = expandAroundCenter(s, i, i);  //奇数情况
            }
            d.emplace_back(cur_d);

            if (i + cur_d > right){
                left = i - cur_d;
                right = i + cur_d;
            }
            
            if (right - left > end - start){
                start = left;
                end = right;
            }
        }
        string res;
        for (int i = start; i <= end; ++i){
            if (s[i] != '#'){
              res += s[i];  
            }
        }
        return res;
    }
};
写法二: 维护盒子 中心下标 和 右侧下标
class Solution {
public:
    // 子模块
    int expandAroundCenter(const string &s, int left, int right){
        while (left >= 0 and right <= s.size() - 1 && s[left] == s[right]){
            --left;
            ++right;
        }
        return (right - left - 2)/2; // 返回 回文半径
    }

    // 主模块
    string longestPalindrome(string s) {
        // 修改 s   统一成 奇长度
        string t = "#";
        for (char c : s){
            t += c;
            t += '#';
        }
        t += '#';
        s = t;

        // 存储 回文半径
        vector<int> d;
        d.emplace_back(1);
        int start = 0, end = -1; // 最长 回文串 的起止下标
        int center = 0, right = -1;  // 盒子 的 中间下标 和 右侧下标
        for (int i = 1; i < s.size(); ++i){
            int cur_d;
            if (i <= right){
                int mirror_left = 2 * center - i;
                int min_d = min(d[mirror_left], right-i);
                cur_d = expandAroundCenter(s, i - min_d, i + min_d);
            }
            else{
                cur_d = expandAroundCenter(s, i, i);   // 盒子外, 中心扩展
            }
            d.emplace_back(cur_d);

            if (i + cur_d > right){
                center = i;
                right = i + cur_d;
            }

            // 更新 最长 回文串 的起止下标
            if (2 * cur_d + 1 > end - start){
                start = i - cur_d;
                end = i + cur_d;
            }
        }
        string res;
        for (int i = start; i <= end; ++i){ // 注意 起止
            if (s[i] != '#'){
                res += s[i];
            }
        }
        return res;
    }
};
Manacher(马拉车) 法 理解 参考

参考链接:https://www.bilibili.com/video/BV173411V7Ai/?spm_id_from=333.337.search-card.all.click&vd_source=f722c145eae91a5b6df588c0ca0f6dbb

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

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

相关文章

网工内推 | 急招网工,思科、华为认证优先,法定节假日三薪

01 江苏臻云技术 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、负责落实数据中心机房日常网络监测及巡检任务&#xff1b; 2、负责数据中心网络设备日常监控、变更、维护、巡检&#xff1b; 3、负责日常巡检报告、故障维护报告、变更申请的文档的编制&#xff1b;…

番外8.2 --- 后续

### 01&#xff1a;dd命令&#xff1a;在新挂载点创建swap文件大小10MB&#xff1b;&#xff08;dd if/dev/zero of/swap bs1024 count10240&#xff09; 02&#xff1a;给swap建立文件系统&#xff0c;将其分属到swap文件&#xff08;mkswap /swap&#xff1b; swapon /swap &…

下载视频号安装,下载视频号安装到手机上?

在数字化时代&#xff0c;随着社交媒体的蓬勃发展&#xff0c;视频内容正成为品牌传播和用户吸引的重要方式。而作为当下最热门的短视频平台之一&#xff0c;视频号为用户提供了创作、分享和推广优质内容的机会。如果您还不了解视频号视频或想进一步了解如何下载视频号视频&…

多测师肖sir_高级金牌讲师__接口测试之练习题(6.1)

常见的接口面试题目: 1.postman接口测试&#xff0c;它有一个功能可以设置参数化&#xff0c;你有用过吗? 用过 &#xff08;1&#xff09;新建一个csv.文件 填写user、pwd 新建一个全局变量 user、pwd 点击bodyform-data 填写user、pwd 点击run 导入csv.件 查看结果 &#x…

element-ui vue2 iframe 嵌入外链新解

效果如图 实现原理 在路由中通过 props 传值 {path: /iframe,component: Layout,meta: { title: 小助手, icon: example },children: [{path: chatglm,name: chatglm,props: { name: chatglm,url: https://chatglm.cn },component: () > import(/views/iframe/common),me…

Facebook广告效果数据获取

一、背景 公司每年在Facebook和Google上投放了大量的广告&#xff0c;我总不能让老板登录Facebook广告投放平台上去看广告效果&#xff0c;其实老板只关注每天花了多少钱引来了多少客户&#xff0c;每个客户平均花费多少钱&#xff0c;其它的他才不关心&#xff0c;有Facebook…

如何将Mysql数据库的表导出并导入到另外的架构

如何将Mysql数据库的表导出并导入到另外的架构 准备一、解决方法1.右键->导出->用mysqldump导出2.注意路径一般为&#xff1a;C:/Program Files/MySQL/MySQL Server 8.0/bin/mysqldump.exe和导出的sql文件位置3.右键->SQL脚本->运行SQL脚本4.找到SQL脚本并点击确定…

C++基础:函数模板

为了代码重用&#xff0c;代码必须是通用的&#xff1b;通用的代码就必须不受数据类型的限制。那么我们可以把数据类型改为一个设计参数&#xff0c;这种类型的程序设计称为参数化程序设计&#xff0c;软件模板有模板构造&#xff0c;包括函数模板和类模板。 函数模板可以用来…

Facebook账号被封?那是因为没做对这些事

Facebook是全球最大的社交媒体平台之一&#xff0c;拥有数十亿的全球用户。它的主要产品包括Facebook&#xff08;面向个人用户的社交媒体平台&#xff09;、Instagram、WhatsApp和Messenger。同时他也是美国数字广告市场的主要参与者之一&#xff0c;其广告平台吸引了数百万广…

H5营销观察:H5破圈传播有什么秘诀

在移动互联网时代&#xff0c;流量越加碎片化&#xff0c;场景变得相对短促和兴趣导向&#xff0c;一个营销H5产生的每一次点击、每一次互动、每一次流量停留背后都会有相应的动机&#xff0c;也是营销流量效果的成因。 今天&#xff0c;我们一起来探究下什么样的内容更容易传播…

微信小程序:点击按钮出现右侧弹窗

效果 代码 wxml <!-- 弹窗信息 --> <view class"popup-container" wx:if"{{showPopup}}"><view class"popup-content"><!-- 弹窗内容 --><text>这是一个右侧弹窗</text></view> </view> <…

系列十四、Spring如何处理线程安全问题

一、线程安全问题出现的原因 Spring中出现线程安全的原因是&#xff0c;单实例bean中存在成员变量&#xff0c;并且有对这个bean进行读写的操作&#xff0c;因此出现了线程安全的问题。 二、案例代码 2.1、MySpringConfig /*** Author : 一叶浮萍归大海* Date: 2023/10/24 1…

【软考】系统集成项目管理工程师(九)项目成本管理【4分】

一、成本概念 1、产品全生命周期成本 产品或系统的整个使用生命周期内&#xff0c;在获得阶段&#xff08;设计、生产、安装和测试等活动&#xff0c;即项目存续期间&#xff09;、运营与维护、生命周期结束时对产品的处置所发生的全部成本 2、成本类型 成本类型描述可变成…

基于 ARM+FPGA+AD平台的多类型同步信号采集仪开发及试验验证(二)板卡总体设计

2.2 板卡总体设计 本章开发了一款基于 AD7193RJ45 的多类型传感信号同步调理板卡&#xff0c;如图 2.4 所 示&#xff0c;负责将传感器传来的模拟电信号转化为数字信号&#xff0c;以供数据采集系统采集&#xff0c;实现了 单通道自由切换传感信号类型与同步采集多类型传…

在进行自动化测试,遇到验证码的问题,怎么办?

1.找开发去掉验证码或者使用万能验证码 2.使用OCR自动识别 使用OCR自动化识别&#xff0c;一般识别率不是太高&#xff0c;处理一般简单验证码还是没问题 这里使用的是Tesseract-OCR,下载地址&#xff1a;https://github.com/A9T9/Free-Ocr-Windows-Desktop/releases 怎么使…

北邮22级信通院数电:Verilog-FPGA(7)第七周实验(1):带使能端的38译码器全加器(关注我的uu们加群咯~)

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 关注作者的uu们可以进群啦~ 目录 方法一&#xff…

huoshan device_id和iid生成记录学习分析

huoshan 和 douyin 作为字节系的产品&#xff0c;device_id 和 iid是抓包经常遇到的字段&#xff0c;代表了设备的概念。 还是熟悉的接口&#xff0c;像 device_register &#xff0c;app_alert_check 和 app_notice_status 都需要请求一遍。 这些接口跑完一遍&#xff0c;设…

信息科技风险管理:合规管理、技术防控与数字化

⭐简单说两句⭐ 作者&#xff1a;后端小知识 CSDN个人主页&#xff1a;后端小知识 &#x1f50e;GZH&#xff1a;后端小知识 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 信息科技对金融业务发展所起的作用是举足轻重的。近年来&#xff0c…

什么是恶意代码?

前言&#xff1a;本文旨在分享交流技术&#xff0c;在这里对恶意代码进行全面的介绍和讲解 目录 一.什么是恶意代码 二.恶意代码的发展史 三.恶意代码的相关定义 四.恶意代码攻击机制 PE病毒 PE文件的格式 脚本病毒 脚本文件隐藏方法 宏病毒 浏览器恶意代码 U盘病毒 …

第13期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练 Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大型语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以…