5. Longest Palindromic Substring

题目描述

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

输入与输出

class Solution {
public:
    string longestPalindrome(string s) {
        
    }
};

样例

  1. Input:"babad",Output:"bab",Note:"aba" is also a valid answer。
  2. Input:"cbbd",Output:"bb"。

题解与分析

解法一

鉴于 s 的最大长度为1000,可以考虑暴力解法,即枚举每一个可能的中间位置,分别向两侧扩展,得到以该位置为中心的最长回文字串。枚举过程中记录最长回文子串的信息,最后返回子串即可。

该解法中需要注意的一点:回文子串的长度的奇偶性不确定,因此每个位置需要两次扩展过程。

C++ 代码如下:

class Solution {
public:
    string longestPalindrome(string s) {
        int size = s.size();
        int start = -1, length = 0; // 维护最长回文子串相关信息
        // 枚举可能的中心位置
        for (int i = 0; i < size; ++i) {
            // 回文子串长度为奇数的情况
            int left = i - 1, right = i + 1;
            while (left >= 0 && right < size && s[left] == s[right])
                --left, ++right;
            if (right - left - 1 > length)
                start = left + 1, length = right - left - 1;
            // 回文子串长度为偶数的情况
            left = i, right = i + 1;
            while (left >= 0 && right < size && s[left] == s[right])
                --left, ++right;
            if (right - left - 1 > length)
                start = left + 1, length = right - left - 1;
        }
        return s.substr(start, length);
    }
};

该解法的时间复杂度为 O(n^2)

解法二

3. Longest Substring Without Repeating Characters 类似,上述解法的时间复杂度高达 O(n^2) 的原因是没有利用之前枚举过程中得到的信息,导致大量重复的判断。

下面介绍 Manacher 算法,该算法的时间复杂度为 O(n),缺点是只能处理长度为奇数的回文子串(可以预处理字符串使该算法也适用于偶数长度子串)。

预处理过程:在原字符串两端与字符之间插入原字符串中未出现过的字符(本文中使用 '#'),例如 abacabba 处理后为 #a#b#a#c#a#b#b#a#。这样所有的回文子串均为奇数长度,例如 #a#b#a##a#b#b#a#

设处理过的字符串为 Ma,建立一个同等长度的 int 数组 MpMp[i]用来记录以位置i为中心的最长回文子串的右半部分的长度(不包括位置i本身),例如#a#b#b#a#的右半部分为b#a#,相应地,Mp[i] = 4。通过上例还可以得到Mp数组的另一个意义,它记录了相应回文子串在原字符串对应的长度。

除此之外,建立变量Mx用来记录当前所有扩展过程中涉及到的最右侧字符的位置,建立变量Id记录扩展到该位置时的中心位置。

下面分情况讨论该算法如何利用之前枚举过程中的信息,也是该算法的核心,对应代码Mp[i] = Mx > i ? min(Mp[2 * Id - i], Mx - i) : 0;

  • 首先判断Mxi的位置关系:
  • Mx > i:说明之前某个回文子串曾经扩展到该位置右侧,则该位置两侧字符中有一部分信息之前获取过。这部分信息保存在Mp[2 * id - i]中,其中2 * id - ii关于Id的对称位置。进一步讨论:
  • Mp[2 * Id - i] <= Mx - i:即以2 * id - i为中心的最长回文子串在以id为中心的最长回文子串内部,如下图所示:

    由于橙色部分是回文子串,那么两个红色部分是镜像关系,如果左侧红色部分是最长回文子串,那么右侧红色部分也是对应位置的最长回文子串。即Mp[i] = Mp[2 * Id - i]
  • Mp[2 * Id - i] > Mx - i:即以2 * id - i为中心的最长回文子串的左侧超出了以id为中心的最长回文子串。如下图所示:

    与上种情况类似,但是以2 * id - i为中心的最长回文子串中只有红色部分在以id为中心的最长回文子串内部,因此右侧对应的红色部分也是回文子串。但是在Mx右侧的字符尚未拓展,因此需要进一步拓展获得最大回文子串。初始化Mp[i] = Mx - i
  • Mx <= i:这种情况下i右侧的字符尚未拓展过,需要拓展获得最长回文子串。初始化Mp[i] = 0

C++ 代码如下:

class Solution {
public:
    string longestPalindrome(string s) {
        int size = s.size() * 2 + 1;
        char *Ma = new char[size];
        int *Mp = new int[size];
        int Mx = -1, Id = -1;
        int start, length = 0;
        Ma[0] = '#';
        for (int i = 0, p = 0; i < s.size(); ++i) {
            Ma[++p] = s[i];
            Ma[++p] = '#';
        }
        for (int i = 0; i < size; ++i) {
            Mp[i] = Mx > i ? min(Mp[2 * Id - i], Mx - i) : 0;
            while (i - Mp[i] - 1 >= 0 && i + Mp[i] + 1 < size && Ma[i - Mp[i] - 1] == Ma[i + Mp[i] + 1])
                ++Mp[i];
            if (i + Mp[i] > Mx)
                Mx = i + Mp[i], Id = i;
            if (Mp[i] > length)
                length = Mp[i], start = (i - Mp[i]) / 2;
        }
        delete[] Ma;
        delete[] Mp;
        return s.substr(start, length);
    }
};

时间复杂度分析:上述代码中,第一个 for 循环为 O(n),第二个 for 循环外层为 O(n),下面分析内部的 while 循环。由上述算法流程可知,每一次扩展操作都是在Mx右侧扩展,即每执行一次++Mp[i];都会导致Mx增加 1,即Mx单调递增。因为Mx的取值范围是[0, size),所以 while 循环内部代码最多执行 O(n) 次。

该解法的时间复杂度为 O(n)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容