5. 最長回文子串

給定一個字符串 s舀透,找到 s 中最長的回文子串谬返。你可以假設 s 的最大長度為1000旭等。

示例 1:

輸入: "babad"
輸出: "bab"
注意: "aba"也是一個有效答案俄删。

示例 2:
輸入: "cbbd"
輸出: "bb"

解法一:暴力解法
時間復雜度O(n^3)
兩個for循環(huán),一個判斷是否為回文的函數(shù)


解法二:中心擴展解法

時間復雜度O(n^2)鹃唯,空間復雜度O(1)
c++ code:

#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<sstream>
#include<assert.h>
using namespace std;

class Solution {
public:
    string expand(string s,int left, int right)
    {
        int len = s.size();
        while (  left>=0&& right < len &&s[left] == s[right])//must s[left] == s[right] allocate last,unless crossing
        {
            left--;
            right++;

        }
        return s.substr(left + 1, right - left - 1);
    }
    string longestPalindrome(string s) {
        int len = s.size();
        if (len < 1) return "";
        if (len == 1) return s;

        string maxstr=s.substr(0,1);
        for (int i = 0; i < len; i++)
        {
            string s1 = expand(s, i, i);
            if (s1.size()>maxstr.size())//odd number
            {
                maxstr = s1;
            }
            string s2 = expand(s, i, i + 1);//even number
            if (s2.size()>maxstr.size())
            {
                maxstr = s2;
            }
        }
        return maxstr;
    }
     
};

string stringToString(string input) {
    assert(input.length() >= 2);
    string result;
    for (int i = 1; i < input.length() - 1; i++) {
        char currentChar = input[i];
        if (input[i] == '\\') {
            char nextChar = input[i + 1];
            switch (nextChar) {
            case '\"': result.push_back('\"'); break;
            case '/': result.push_back('/'); break;
            case '\\': result.push_back('\\'); break;
            case 'b': result.push_back('\b'); break;
            case 'f': result.push_back('\f'); break;
            case 'r': result.push_back('\r'); break;
            case 'n': result.push_back('\n'); break;
            case 't': result.push_back('\t'); break;
            default: break;
            }
            i++;
        }
        else {
            result.push_back(currentChar);
        }
    }
    return result;
}

int main() {
    string line;
    while (getline(cin, line)) {
        string s = stringToString(line);

        string ret = Solution().longestPalindrome(s);

        string out = (ret);
        cout << out << endl;
    }
    return 0;
}
中心擴展test

substr
   Returns a substring (pos, pos+count).pos開始的位置,count共有多少個瓣喊。


解法三:動態(tài)規(guī)劃
時間復雜度O(n^2)坡慌,空間復雜度O(n^2)

核心思路就是從左開始遍歷,然后不斷的從原字符串中拿出1到length-1長度的字串藻三,進行判斷洪橘。 回文字符串的子串也是回文,比如dp[j,k](表示以i開始以j結(jié)束的子串)是回文字符串棵帽,那么dp[j+1,k-1]也是回文字符串熄求。這樣最長回文子串就能分解成一系列子問題了。
  動態(tài)規(guī)劃需要開一個二維數(shù)組逗概,DP[j][k]= s[j]==s[k]&&DP[j+1][k-1]弟晚,時間復雜度較高

初始化:
\begin{cases} dp[j][j] = true & \text{(0 <= j <= n-1)}\\ dp[j][j+1] = true & \text{(0 <= j <= n-1,if s[j]==s[j+1])}\\ others = fasle \end{cases}

轉(zhuǎn)移函數(shù)
dp[j][k] = \begin{cases} dp[j+1][k-1], & \text{if s[j] == s[k]} \\ false, & \text{if s[j] ≠ s[k]} \end{cases}

class Solution {
public:

    string longestPalindrome(string s) {
        int len = s.size();
        if (len < 1) return "";

        vector<vector<int>>Flaglen(len, vector<int>(len, 0));
        int maxlen = 0, index = 0;
        for (int i = 0; i < len; i++)
        for (int j = 0, k = i; j < len&&k < len; j++, k++)
        {
            if (j == k)Flaglen[j][k] = 1;//odd
            else if (j + 1 == k&&s[j] == s[k])
            {
                Flaglen[j][k] = 2;//even
            }
            else if (s[j] == s[k] && Flaglen[j + 1][k - 1])
            {
                Flaglen[j][k] = Flaglen[j + 1][k - 1] + 2;
            }
            else
            {
                Flaglen[j][k] = 0;
            }
            if (Flaglen[j][k]>maxlen)
            {
                index = j;
                maxlen = k - j + 1;
            }
        }
        return s.substr(index, maxlen);
    }


};
動態(tài)規(guī)劃test

解法四:1975年,Manacher算法(馬拉車)
時間復雜度 O(n)
1.解決長度奇偶性帶來的對稱軸位置問題
   插入#解決

string init(string s)
{
    string s1="$#";
    int len=s.size();
    int i;
    for(i=0;i<len;i++)
    {
        s1+=s[i];
        s1+="#";
    }

    return s1;
}

2.解決重復訪問的問題
   利用最長id中心的當前i點的對稱點j


好好思考體會這句代碼:

if (i < mx)  
    p[i] = min(p[2 * id - i], mx - i);

step 1: 令p[i]=min(p[2*pos-i], mx-i)
step 2: 以i為中心擴展回文串逾苫,直到左右兩邊字符不同卿城,或者到達邊界。
step 3: 更新mx和id

示例:#a##a#a#回文半徑分別是2和3铅搓,所以無論奇偶都是 瑟押,p[i] - 1正好是原字符串中最長回文串的長度。
解釋:原始字符串的最大子串狸吞,起始位置的索引centermax - maxlen) / 2勉耀,用下面的圖驗證指煎。除以2是因為加入相同數(shù)的#。

舉例驗證

0 1 2 3 4 5 6 7 8
a b b a h o x p x

驗證1:i=5,abba. centermax=5,maxlen=4,pos=0
驗證2:i=16,pxp, centermax=16,maxlen=3,pos=6

class Solution {
public:
    string init(string s)
    {
        string s1 = "$#";//$防越界
        int len = s.size();
        for (int i = 0; i < len; i++)
        {
            s1 += s[i];
            s1 += '#';
        }
        return s1;
    }
    string longestPalindrome(string s) {
        int len1 = s.size();
        if (len1 < 1) return "";

        
        string s_new=init(s);
        int len = s_new.size();
        vector<int>p(len, 0);
        int id = 0, mx = 0;
        for (int i = 1; i < len; i++)//i從1開始忽略$
        {
            if (i < mx)
            {
                p[i] = min(p[2 * id-i], mx - i);
            }
            else//i在mx右邊 必須一個個匹配
            {
                p[i] = 1;
            }
            while (s_new[i - p[i]] == s_new[p[i] + i])
                p[i]++;
            /*我們每走一步 i便斥,都要和 mx 比較至壤,我們希望 mx 盡可能的遠,
            這樣才能更有機會執(zhí)行 if (i < mx)這句代碼枢纠,從而提高效率*/
            if (mx < i + p[i])
            {
                mx = i + p[i];
                id = i;
            }
        }
        /*找最大元素在P中*/
        int centermax = 0, maxlen = 0;
        for (int i = 1; i < len; i++)
        {
            if (p[i] - 1>maxlen)
            {
                maxlen = p[i] - 1;
                centermax = i;
            }
        }
        return s.substr((centermax - maxlen) / 2, maxlen);
    }


};
精益求精99.78%







參考1 此鏈接中心擴展ok像街,動態(tài)規(guī)劃有問題。

參考2
參考3
參考4
Manacher

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末晋渺,一起剝皮案震驚了整個濱河市镰绎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌木西,老刑警劉巖畴栖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異八千,居然都是意外死亡吗讶,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門恋捆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來照皆,“玉大人,你說我怎么就攤上這事沸停∧せ伲” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵愤钾,是天一觀的道長瘟滨。 經(jīng)常有香客問我,道長能颁,這世上最難降的妖魔是什么室奏? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮劲装,結(jié)果婚禮上胧沫,老公的妹妹穿的比我還像新娘。我一直安慰自己占业,他們只是感情好绒怨,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谦疾,像睡著了一般南蹂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上念恍,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天六剥,我揣著相機與錄音晚顷,去河邊找鬼。 笑死疗疟,一個胖子當著我的面吹牛该默,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播策彤,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼栓袖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了店诗?” 一聲冷哼從身側(cè)響起裹刮,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎庞瘸,沒想到半個月后嵌洼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體菠净,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡胰蝠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年图焰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霜第。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖户辞,靈堂內(nèi)的尸體忽然破棺而出泌类,到底是詐尸還是另有隱情,我是刑警寧澤底燎,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布刃榨,位于F島的核電站,受9級特大地震影響双仍,放射性物質(zhì)發(fā)生泄漏枢希。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一朱沃、第九天 我趴在偏房一處隱蔽的房頂上張望苞轿。 院中可真熱鬧,春花似錦逗物、人聲如沸搬卒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽契邀。三九已至,卻和暖如春失暴,著一層夾襖步出監(jiān)牢的瞬間坯门,已是汗流浹背微饥。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留古戴,地道東北人欠橘。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像允瞧,于是被迫代替她去往敵國和親简软。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 題目 給定一個字符串 s述暂,找到 s 中最長的回文子串痹升。你可以假設 s 的最大長度為1000。 示例 1: 輸入: ...
    sxqiong閱讀 43,327評論 11 18
  • https://leetcode-cn.com/problems/longest-palindromic-subs...
    coconutyao閱讀 258評論 1 1
  • 一畦韭、題目原型: 給定一個字符串 s疼蛾,找到 s 中最長的回文子串。你可以假設 s 的最大長度為1000艺配。 二察郁、題目意...
    花果山松鼠閱讀 412評論 0 0
  • 給定一個字符串 s,找到 s 中最長的回文子串转唉。你可以假設 s 的最大長度為1000皮钠。 示例 1: 示例 2: 這...
    閉門造折閱讀 333評論 0 0
  • 作家馮唐抖出一個油膩中年的概念,引的一片嘩然赠法。人到中年麦轰,一旦油膩,肯定是滑潤了砖织,看上去光溜溜款侵,摸上去滑溜溜...
    維維心誠軒逸若彬閱讀 322評論 0 0