最长回文子串(动规,中心扩散法,Manacher算法)

题目

leetcode:5.?Longest Palindromic Substring

解法

动态规划

时间复杂度\(O(n^2)\),空间复杂度\(O(n^2)\)
基本解法直接看代码

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        vector<vector<bool>> dp(n, vector<bool>(n, true));
        int rx, ry;

        rx = ry = 0;
        for(int l = 1; l < n; l++){
            for(int i = 0; i < n - l; i++){
                int j = i + l;
                if(s[i] == s[j] && (j - i < 3 || dp[i+1][j-1])){
                    dp[i][j] = true;
                    if(j - i > ry - rx){
                        ry = j;
                        rx = i;
                    }
                } else {
                    dp[i][j] = false;
                }
            }
        }

        return s.substr(rx, ry - rx + 1);
    }
};

中心扩散法

时间复杂度\(O(n^2)\),空间复杂度\(O(1)\)
我们先假定以某点为中心向两端扩散,找到以该点为中心的最长回文子串

class Solution {
public:

    int rx, ry;
    void helper(string &s, int i, int offset){
        int left = i;
        int right = i + offset;
        while(left >= 0 && right < s.size() && s[left] == s[right]){
            left--;
            right++;
        }

        if(right - 1 - (left + 1) > ry - rx){
            ry = right - 1;
            rx = left + 1;
        }
    }
    string longestPalindrome(string s) {
        int n = s.size();

        rx = ry = 0;

        for(int i = 0; i < n; i++){
            helper(s, i, 0);
            helper(s, i, 1);
        }

        return s.substr(rx, ry - rx + 1);
    }
};

Manacher算法

Manacher算法俗称“马拉车算法”,时间复杂度\(O(n)\),空间复杂度\(O(n)\)
因为回文字符串都有奇数长度的串和偶数长度的串,为了更好处理这两种情况,可以在字符串中插入一特殊字符‘#‘,使得新字符串长度全变为奇数长度,如"aa"变为"#a#a#",可以再字符串首部加入另一特殊字符‘$‘和尾部的‘@‘,这样就不用特殊处理越界问题(统一边界处理)
以"122112321"为例经过上一步变成"@#1#2#2#1#1#2#3#2#1#"
Manacher算法使用一个辅助数组r[i]表示以t[i]为中心的最长回文子串的最右字符到t[i]的长度,如以t[i]为中心的最长回文子串为t[low, high],则r[i] = high - i + 1, t[low, high] = 2 * r[i]-1, len数组有一个性质,就是r[i]-1为该回文子串在原串中的长度,证明很简单t[lowl, high]一定是以"#"开头和结尾的,这样插入的"#"是原来串中字符的两倍还多一个,这样原串中最长回文串的长度就为r[i]-1,这样问题就转为求最长的r[i]

计算len数组

算法主要利用了已有的回文子串的特点,减少了查找时间,从左往右计算len[i],同时保存一个之前计算最长回文子串的右端点的最大值R及对应的中心位置c,

  • i < R, 则先找i关于c对称点j=2*c-i,则至少r[i] \(\geq\) min(R - i + 1, p[j]), 超出部分再手工匹配
  • i >= R, 则不能利用以后的知识做任何假设,只能假定其至少为1,再手工匹配
class Solution {
public:

    string longestPalindrome(string s) {
        int n = s.size();
        if(n == 0) return "";
        string ns;
        ns.push_back('$');
        for(int i = 0; i < n; i++){
            ns.push_back('#');
            ns.push_back(s[i]);
        }
        ns.push_back('#');
        ns.push_back('@');
        n = ns.size();
        vector<int> r(n);
        int c, R, C, MAX;
        R = -1;
        MAX = 0;
        C = 0;
        for(int i = 1; i < n; i++){
            r[i] = i < R ? min(r[2 * c - i], R - i + 1) : 1;
            while(ns[i + r[i]] == ns[i - r[i]]) r[i]++;
            r[i]--;
            if(i + r[i] > R){
                R = i + r[i];
                c = i;
            }
            if(r[i] > MAX){
                MAX = r[i];
                C = i;
            }

        }

        return s.substr((C-MAX)/2, r[C]);
    }
};
时间复杂度分析

参考

原文地址:https://www.cnblogs.com/qbits/p/11229279.html

时间: 2024-10-19 05:30:43

最长回文子串(动规,中心扩散法,Manacher算法)的相关文章

【转】最长回文子串的O(n)的Manacher算法

Manacher算法 首先:大家都知道什么叫回文串吧,这个算法要解决的就是一个字符串中最长的回文子串有多长.这个算法可以在O(n)的时间复杂度内既线性时间复杂度的情况下,求出以每个字符为中心的最长回文有多长,    这个算法有一个很巧妙的地方,它把奇数的回文串和偶数的回文串统一起来考虑了.这一点一直是在做回文串问题中时比较烦的地方.这个算法还有一个很好的地方就是充分利用了字符匹配的特殊性,避免了大量不必要的重复匹配.    算法大致过程是这样.先在每两个相邻字符中间插入一个分隔符,当然这个分隔符

Leetcode-最长回文子串(包含动态规划以及Manacher算法)

原文地址: https://www.cnblogs.com/mini-coconut/p/9074315.html 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为1000. 示例 1: 输入: "babad" 输出: "bab" 注意: "aba"也是一个有效答案. 示例 2: 输入: "cbbd" 输出: "bb" 自己的思路:求一个字符串的最长回文子串,我们可以将以每个字符

最长回文子串 (动态规划法、中心扩展算法)

问题描述: 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为1000. 思考: 嗯,回文嘛!就是顺序读取和逆序读取的结果是一样的,那我们可以使用两个for循环来不断的截取给定的字符串S,然后判断截取后的字符串是不是回文串,与此同时,使用一个新的字符串result来保存我们截取到的并且长度最长的回文串. 代码: public String longestPalindrome_reconstructure1(String s){ // 超出时间限制 if (s.lengt

《算法竞赛入门经典》3.3最长回文子串

1 //例题3-4 2 /* 3 * 输入一个字符串,求出其中最长的回文子串.子串的含义是:在原串中连续出现的字符串片段. 4 *回文的含义是:正看着和倒看着相同,如abba和yyxyy.在判断时,应该忽略所有标点符号和空格 5 *且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符).输入字符长度不超过5000 6 *且占据单独的一行.应该输出最长回文串,如果有多个,输出起始位置最靠左的. 7 *样例输入:Confuciuss say:Madam,I'm Adam. 8 *样例

Manacher算法----最长回文子串

题目描述 给定一个字符串,求它的最长回文子串的长度. 分析与解法 最容易想到的办法是枚举所有的子串,分别判断其是否为回文.这个思路初看起来是正确的,但却做了很多无用功,如果一个长的子串包含另一个短一些的子串,那么对子串的回文判断其实是不需要的.同时,奇数和偶数长度还要分别考虑. Manacher算法可以解决上述问题,并在O(n)时间复杂度内求出结果.下面我们来看一下Manacher算法. 首先,为了处理奇偶的问题,在每个字符的两边都插入一个特殊的符号,这样所有的奇数或偶数长度都转换为奇数长度.比

[hiho 01]最长回文子串、Manacher算法

题目描述 - 基础方法:枚举子串,判断是否为回文串. - 改进:枚举中间位置,向两侧拓展. - 再改进:利用以前的信息,使得不用每个新位置都从长度1开始拓展. - 优化:将字符串预处理为奇数长度以避免考虑条件分支. - 再优化:开头加入特殊字符避免考虑边界. Manacher 算法: id 是中心点,mx 是其边界.P[i] 表示以 i 为中心的最长回文子串的折半长度. 只要 i < mx, 以 i 为中心的回文子串就可以不必从长度1开始找,而从min{P[j], mx - i}开始(其中j为i

[译]最长回文子串(Longest Palindromic Substring) Part II

[译+改]最长回文子串(Longest Palindromic Substring) Part II 问题:给定字符串S,求S中的最长回文子串. 在上一篇,我们给出了4种算法,其中包括一个O(N2)时间O(1)空间的算法(中心检测法),已经很不错了.本篇将讨论一个O(N)时间O(N)空间的算法,即著名的Manacher算法,并详细说明其时间复杂度为何是O(N). 提示 +BIT祝威+悄悄在此留下版了个权的信息说: 先想想有什么办法能改进中心检测法. 考虑一下最坏的情况.★ 最坏的情况就是各个回文

最长回文子串(转自:hihoCoder)

#1032 : 最长回文子串 时间限制:1000ms 单点时限:1000ms 内存限制:64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:"小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?" 小Ho奇怪的问道:"什么叫做最长回文子串呢?" 小Hi回答道:"一个字符串中连续的一

URAL-1297 Palindrome (最长回文子串)

Palindrome Time Limit: 1000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Description The “U.S. Robots” HQ has just received a rather alarming anonymous letter. It states that the agent from the competing «Robots Unlimited» has infiltrat