回文子串&最長公共子串

一個字符串的子串是字符串中連續(xù)的一個序列爪飘,而一個字符串的子序列是字符串中保持相對位置的字符序列,譬如嘲玫,"adi"可以使字符串"abcdefghi"的子序列但不是子串悦施。這也就決定了在解這兩種"LCS"問題上的一些區(qū)別。
Longest-Common-Substring和Longest-Common-Subsequence是不一樣的去团。

之前我寫的時候這兩個概念有錯誤抡诞,見諒。

把子序列改成字串后條件更嚴苛了土陪,某些情況下解題的復雜度也低一些昼汗。

回文子串

比如drabfbaz里面abfba就是回文的,長度為5.

思路1:逐個字母判斷

我們以每個字母為中心鬼雀,逐個判斷字符兩邊的回文長度顷窒。

由于比較簡單,就不多說了:

//solution1: make i as center and extends 
int solution1(char* s) 
{
    int n=strlen(s);
    int i=0,j=0;
    int curmax=0,max=0;
    for(i=0;i<n;i++)
    {
        for(j=0;i-j>=0&&i+j<n;j++)//j is the length of substr
        {
            //odd length
            if(s[i+j]!=s[i-j])
            break;
            curmax=j*2+1;
        }
            if(curmax>max)
            max=curmax;
        for(j=0;i-j>=0&&i+j+1<n;j++)//j is the length of substr
            {
                //even length:
                if(s[i-j]!=s[i+j+1])
                break;
                curmax=j*2+2;
            }
                if(curmax>max)
                max=curmax;
        
    }
    return max;
}

解法2:manacher算法

參考:https://www.felix021.com/blog/read.php?2040

我們上面的解法分了奇數(shù)長度和偶數(shù)長度兩種情況討論,并且復雜度也不低鞋吉,我們嘗試著改進一下:

  • 首先鸦做,我們解決奇數(shù)和偶數(shù):我們在字符串里面插入#號后看看發(fā)生了什么:
    abbc->#a#b#b#a# abdba->#a#b#d#b#a#
    這樣所有的都變成了奇數(shù)長度,就可以統(tǒng)一處理了谓着。

  • 我們還可以在字符串首加入另一個符號比如$來將字符串的下標0轉換為更熟悉的下標1泼诱。

以字符串12212321為例,經(jīng)過上一步赊锚,變成了 S[] = "$#1#2#2#1#2#3#2#1#";

  • 然后用一個數(shù)組 P[i] 來記錄以字符S[i]為中心的最長回文子串向左/右擴張的長度(包括S[i]治筒,也就是把該回文串“對折”以后的長度),比如S和P的對應關系:
    S # 1 # 2 # 2 # 1 # 2 # 3 # 2 # 1 #
    P 1 2 1 2 5 2 1 4 1 2 1 6 1 2 1 2 1
    (p.s. 可以看出舷蒲,P[i]-1正好是原字符串中回文串的總長度)

  • 所以我們的問題轉化為耸袜,如何計算p[i]的值

  • 我們來發(fā)現(xiàn)一條規(guī)律,來從一定程度上簡化計算:
    假如我們位置為id的地方牲平,其長度為p[id]堤框,記右邊界為mx=id+p[id];
    (實際上是mx-1吧)
    那么其左邊界就是id-p[id]

  • 假設有一個位置i,其正好在id這個字符為中心的回文字符串里面(i<mx)纵柿,那么根據(jù)回文的對稱性胰锌,其左邊會有一個與之對稱的位置j,j=2*id-i藐窄;

位置關系
  • 那么這個能干什么呢资昧?因為我們是從左往右邊求的,所以直接可以得到右邊位置i的最小回文長度荆忍!
    因為回文的對稱性格带,左邊的長度如果是x的話,且j-x>mx的對稱點刹枉,即位置j的回文子串全部在以id為中心的字符串里面的話叽唱,可以推出以i為中心的回文字符串的長度最小也是j的回文長度p[j];

  • 但是如果j的回文字符串超出了mx對稱點的邊界微宝,也可以說棺亭,p[i]的值最少為mx-i

  • 得到上述兩種情況的最小長度后,我們再對位置i的字符進行判斷蟋软,是否有更長的字符滿足回文镶摘。

這些思路轉化為代碼就是:

for(i = 1; s[i] != '\0'; i++)
 { 
 p[i] = mx > i ? min(p[2*id-i], mx-i) : 1; 
while(s[i + p[i]] == s[i - p[i]]) 
p[i]++; 
if(i + p[i] > mx) 
{    
mx = i + p[i];    
id = i;  }
}

把之前的內容整理下:

  • 預處理字符串的函數(shù):
char c[1000];
int func(char* s)
{
    if (!s)
        return NULL;
    int n = strlen(s);
    
    c[0] = '$';
    int i = 0, j = 1;
    while (i < n)
    {
        c[j++] = '#';
        c[j++] = s[i++];
    }
    c[j] = '#';
    
    return j;
}

主干:

int solution_manacher(char* s)
{
    if (!s)
        return 0;
    int len = func(s);//length of c
    int i = 1;
    int curmax = 0;
    int p[1000];//p[i] is the length of ith char in c
    p[0] = 0;
    int id=1 , mx = 0;//mx=id+p[id],but id=????????
    for (i = 1; i<len; i++)
    {
        p[i] = 1;
        //if (mx>i)
        //  p[i] = minTwo(mx - i, p[2 * id - i]);//actually pi>=minTwo
        //else p[i] = 1;//one char,itself
        if (mx > i)
        { 
            p[i] = p[2 * id - i];
            if (mx - i < p[i])
                p[i] = mx - i;
        }
        while (c[i + p[i]] == c[i - p[i]])
            p[i]++;
        if (i + p[i]>mx)
        {
            mx = i + p[i];
            id = i;
        }
        if (p[i]>curmax)
            curmax = p[i];
    }
    return curmax-1;
}

最長公共子串

由于這個情況限制只能是連續(xù)的,所以情況要簡單一些岳守,方程也退化為:

l c substring

思路和上次差不多凄敢,也是創(chuàng)建了一個二維數(shù)組:

#include <iostream>

int lcsubstr(char* s1, char* s2)
{
    if (!s1 || !s2)
        return 0;
    int len1 = strlen(s1);
    int len2 = strlen(s2);
    int i = 0, j = 0;

    int max=0;
    int a[100][100];
    memset(a, 0, sizeof(a));
    for (i = 0; i < len1; i++)
    {
        for (j = 0; j < len2; j++)
        {
            if (s1[i] == s2[j])
                a[i + 1][j + 1] = 1+a[i][j];//careful! i+1&j+1
            if (a[i + 1][j + 1]>max)
                max = a[i + 1][j + 1];
        }
    }
    return max;
}
int main()
{
    char s1[] = "abcd";
    char s2[] = "bcdef";
    std::cout << lcsubstr(s1, s2);
}

不知道有沒有bug額。湿痢。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末涝缝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拒逮,老刑警劉巖罐氨,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滩援,居然都是意外死亡岂昭,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門狠怨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人邑遏,你說我怎么就攤上這事佣赖。” “怎么了记盒?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵憎蛤,是天一觀的道長。 經(jīng)常有香客問我纪吮,道長俩檬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任碾盟,我火速辦了婚禮棚辽,結果婚禮上,老公的妹妹穿的比我還像新娘冰肴。我一直安慰自己屈藐,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布熙尉。 她就那樣靜靜地躺著联逻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪检痰。 梳的紋絲不亂的頭發(fā)上包归,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音铅歼,去河邊找鬼公壤。 笑死,一個胖子當著我的面吹牛椎椰,可吹牛的內容都是我干的境钟。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼俭识,長吁一口氣:“原來是場噩夢啊……” “哼慨削!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤缚态,失蹤者是張志新(化名)和其女友劉穎磁椒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體玫芦,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡浆熔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了桥帆。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片医增。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖老虫,靈堂內的尸體忽然破棺而出叶骨,到底是詐尸還是另有隱情,我是刑警寧澤祈匙,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布忽刽,位于F島的核電站,受9級特大地震影響夺欲,放射性物質發(fā)生泄漏跪帝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一些阅、第九天 我趴在偏房一處隱蔽的房頂上張望伞剑。 院中可真熱鬧,春花似錦市埋、人聲如沸纸泄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽聘裁。三九已至,卻和暖如春弓千,著一層夾襖步出監(jiān)牢的瞬間衡便,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工洋访, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留镣陕,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓姻政,卻偏偏與公主長得像呆抑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子汁展,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內容

  • 字符串最長回文子串 題目描述: 給定一個字符串鹊碍,求它的最長回文子串的長度厌殉。 分析和解法: 最容易想到的辦法是枚舉所...
    MinoyJet閱讀 638評論 0 2
  • 最長回文子串——Manacher 算法 1. 問題定義 最長回文字符串問題:給定一個字符串,求它的最長回文子串長度...
    林大鵬閱讀 2,744評論 0 6
  • 上一篇KMP算法之后好幾天都沒有更新侈咕,今天介紹最長回文子串公罕。 首先介紹一下什么叫回文串,就是正著讀和倒著讀的字符順...
    zero_sr閱讀 2,270評論 2 8
  • 首先用一個非常巧妙的方式耀销,將所有可能的奇數(shù)/偶數(shù)長度的回文子串都轉換成了奇數(shù)長度:在每個字符的兩邊都插入一個特殊的...
    Chris_C閱讀 150評論 0 0
  • 計算機二級C語言上機題庫(南開版) 1.m個人的成績存放在score數(shù)組中楼眷,請編寫函數(shù)fun,它的功能是:將低于平...
    MrSunbeam閱讀 6,323評論 1 42