最長回文子串

最長回文子串——Manacher 算法

1. 問題定義

最長回文字符串問題:給定一個字符串甘畅,求它的最長回文子串長度城榛。
如果一個字符串正著讀和反著讀是一樣的,那它就是回文串孙乖。

舉個?? :

  • s="ababa", 最長回文長度為 5浙炼;即ababa
  • s="abccb", 最長回文長度為 4,即 bccb唯袄。

2.暴力解法:

對于最長回文子串問題弯屈,最簡單粗暴辦法是:找到所有字符串的子串,遍歷每一個子串以驗證它們是否為回文串恋拷。一個子串由子串的起點和終點確定资厉,因此對于一個長度為n的字符串,共有n^2個子串蔬顾。這些子串的平均長度大約為n/2宴偿,因此這種解法的時間復雜度是O(n^3)湘捎。

解法:

string findLongestPalindrome(string &s){

   if (s.empty()) {
       return "";
    }

    if (s.size() == 1) {
        return s;
     }
    // 字符串 長度
    unsigned long length = s.size();
    // 最長 回文 字符串 長度
    int maxLength = 0;
    // 最長 回文 字符串 起始地址
    int start = 0;

    for(int i = 0; i < length; i++){
        for (int j = i + 1; j < length; j++) {
            int tmp1, tmp2;
            // 判斷 是不是 回文
            for (tmp1 = i, tmp2 = j; tmp1 < tmp2; tmp1++, tmp2--) {
                if(s.at(tmp1) != s.at(tmp2)){
                    break;
                }
            }
            // 如果 遍歷 到中間 說明這是一個 回文 字符串
            if (tmp1 >= tmp2 && (j-i) >= maxLength) {
                maxLength = j - i + 1;
                start = i;
            }
        }
    }
    if (maxLength > 0) {
        return s.substr(start, maxLength);
    }
    return "";
}

3. 動態(tài)規(guī)劃

回文字符串的子串也是回文,所以對于母串s,我們用p[i][j] = 1(表示以i開始以j結(jié)束的子串)是回文字符串窄刘,那么p[i+1][j-1]也是回文字符串窥妇。

  • 這樣當s[i] = s[j]時,如果p[i+1][j-1]回文子串娩践,則p[i][j]也是回文子串活翩。

  • 如果p[i+1][j-1]不是回文子串或者s[i] != s[j],那么p[i][j]就不是回文子串。

  • 特別地翻伺,對于這樣的字符串——只包含單個字符材泄、或者兩個字符重復,其均為回文串

    p[i][i] = 1;
    c[i][i+1] = 1吨岭, if(s[i] == s[i+1])
    
  • 這樣需要額外的空間o(N^2),算法復雜度也是o(n^2).
    解法:

      static int const arrayLength = 100;
      string findLongestPalindrome(string &s){
          if (s.empty()) {
                return "";
          }
    
          if (s.size() == 1) {
               return s;
          }
          // 字符串 長度
          unsigned long length = s.size();
          // 最長 回文 字符串 長度
          int maxLength = 0;
          // 最長 回文 字符串 起始地址
          int start = 0;
          // 存儲 所有 子字符串
          bool p[arrayLength][arrayLength] = {false};
    
          for(int i = 0; i < length; i++){
              // 單個 字符 為 回文串
              p[i][i] = true;
              // 判斷 兩個字 重復 情況
              if ((i < length - 1) && s.at(i) == s.at(i+1)) {
                  p[i][i + 1] = true;
                  start = i;
                  maxLength = 2;
              }
          }
    
          // 子串 長度(因為已經(jīng)計算了單個或兩個字重復的回文字符串,所以子串長度最低從3開始)
          // 計算 3 - length 所有子串中 所有最長子串
          for(int len = 3; len <= length; len++){
              // 子串 起始 地址
              // 在 字符串 中 找到 所有 長度為 len的子串并判斷
              for (int i = 0; i <= length - len; i++) {
                  int j = i + len - 1;
                  if (p[i+1][j-1] && s.at(i) == s.at(j)) {
                     p[i][j] = true;
                      maxLength = len;
                      start = i;
                  }
              }
          }
          if (maxLength >= 2) {
              return s.substr(start, maxLength);
          }
          return "";
         }
    

這種解法拉宗,當最大的回文子串有多個時,取最后一個辣辫,如果要取第一個旦事,則在 start = i后面加上break;即可。

C語言解法:

static int const arrayLength = 100;
/**
 找到 最長 回文 子串 (動態(tài) 規(guī)劃 方法)
 
 @param string 字符串
 @param stringLength 字符串 長度
 */
void findLongestPalindromeTwo(char *string, int stringLength) {
    if (string == NULL || stringLength == 0) {
        return;
    }
    if (stringLength == 1) {
        printf("%s\n", string);
        return;
    }

    // 回文串 長度
    int maxLength = 0;
    // 起始 位置
    int startPosition = 0;
    // 輔助 數(shù)組(存儲 所有 字符串)
    int helperArray [arrayLength][arrayLength] = {false};
    
    // 循環(huán) 遍歷
    for (int tmpIndex = 0; tmpIndex < stringLength; tmpIndex++) {
        // 單個 字符 為 回文串
        helperArray[tmpIndex][tmpIndex] = true;
        if (string[tmpIndex] == string[tmpIndex + 1]) {
            // 相同 字符 比如 aa 也是 回文串
            helperArray[tmpIndex][tmpIndex + 1] = true;
            startPosition = tmpIndex;
            maxLength = 2;
        }
    }
    
    // 循環(huán) 遍歷
    // 子串 長度(因為已經(jīng)計算了單個或兩個字重復的回文字符串,所以子串長度最低從3開始)
    // 計算 3 - length 所有子串中 所有最長子串
    for (int len = 3; len <= stringLength; len ++) {
        for (int i = 0; i <= stringLength - len; i ++) {
            int j = i + len - 1;
            if (helperArray[i + 1][j - 1] == true && string[i] == string[j]) {
                helperArray[i][j] = true;
                maxLength = len;
                startPosition = i;
            }
        }
    }
    
    if (maxLength > 1) {
        for (int tmpIndex = 0; tmpIndex < maxLength; tmpIndex++) {
            printf("%c", string[startPosition]);
            startPosition++;
        }
        printf("\n");
    }
}

4.中心擴展

  • 很明顯所有的回文字符串都是對稱的;

  • 長度為奇數(shù)回文字符串以最中間字符位置為對稱軸左右對稱络它。

  • 長度為偶數(shù)的回文串以中間兩個字符的空隙為對稱軸對稱族檬。

  • 因此,整個字符串中所有字符化戳,以及字符間的空隙都有可能是某個回文子串的對稱軸位置单料。可以遍歷這些位置点楼,在每個位置上同時向左向右擴展扫尖,直到左右兩邊字符不同或者到達邊界。

  • 對于一個長度為n的字符串掠廓,這樣的位置一共有n+n-1=2n-1個换怖,在每個位置上平均要進行大約n/4次比較,此算法的時間復雜度為o(n^2).

解法:

    string findLongestPalindrome(string &s) {
    
        if (s.empty()) {
            return "";
        }
    
        if (s.size() == 1) {
            return s;
        }
    
        unsigned long length = s.size();
    
        int maxlength = 0;
    
        int start = 0;
    
        string tmpStr = s;
        for(int i = 0,k = 0; i <= length; i++){
            s.insert(k, "#");
            k = k + 2;
        }

        for (int i = 0 ; i < length; i++) {
            // 間隔 兩個 字符
            int j = i - 1, k = i + 1;
            while (j >= 0 && k < length && s.at(j) == s.at(k)) {
                if ((k - j + 1) > maxlength) {
                    maxlength = k - j +1;
                    start = j;
                }
                j--;
                k++;
            }
        }
    
        if(maxlength > 0){
            int tmpMaxLength = (maxLength - 1)/2;
            int tmpStartPostion = start/2;
            return tmpStr.substr(tmpStartPostion,tmpMaxLength);
        }
        return "";
    }

C語言解法:

/**
 找到 最長 回文 子串 (中心 對稱 方法)

 @param string 字符串
 @param stringLength 字符串 長度
 */
void findLongestPalindrome(char *string, int stringLength) {
    if (string == NULL || stringLength == 0) {
        return;
    }
    if (stringLength == 1) {
        printf("%s\n", string);
        return;
    }
    
    // 插入 特殊字符 后字符串 長度
    int tmpStringLength = stringLength * 2 + 1;
    // 開辟 新的字符串
    char *tmpString = malloc(sizeof(char) * tmpStringLength);
    // 新字符串 復制 舊字符串 并在空隙插入 '#'
    tmpString[0] = '#';
    for (int tmpIndex = 0; tmpIndex < stringLength; tmpIndex ++) {
        tmpString[tmpIndex * 2 + 1] = string[tmpIndex];
        tmpString[tmpIndex * 2 + 2] = '#';
    }
    
    // 回文串 長度
    int maxLength = 0;
    // 起始 位置
    int startPosition = 0;
    
    // 遍歷 字符串
    for(int i = 0; i < tmpStringLength; i++) {
        int j = i - 1;
        int k = i + 1;
        while (j >= 0 && k < tmpStringLength && tmpString[j] == tmpString[k]) {
            if (k - j + 1 > maxLength ) {
                maxLength = k - j + 1;
                startPosition = j;
            }
            j --;
            k ++;
        }
    }
    
    if (maxLength > 1) {
        int tmpMaxLength = (maxLength - 1)/2;
        int tmpStartPostion = startPosition/2;
        
        for (int tmpIndex = 0; tmpIndex < tmpMaxLength; tmpIndex++) {
            printf("%c", string[tmpStartPostion]);
            tmpStartPostion++;
        }
        printf("\n");
    }
}

5. Manacher 算法

中心擴展的算法是存在缺陷的:

  • 由于回文字符串的奇偶性造成了不同性質(zhì)的對稱軸位置蟀瞧,因此要分兩種情況進行處理沉颂。

  • 很多子串被重復多次訪問,造成較差的時間效率悦污。
    舉個?? :

    s : a b a b a
    i : 0 1 2 3 4
    

i == 1i == 2時铸屉,左邊的子串a(chǎn)ba分別被遍歷了一次。

A. 解決長度奇偶性帶來的對稱軸位置問題
Manacher算法首先對字符串做一個預處理切端,在所有的空隙位置(包括首尾)插入同樣的符號彻坛,要求這個符號是不會出現(xiàn)在原串中出現(xiàn)的,這樣會使得所有的串都是奇數(shù)長度的。已插入#號為例昌屉。

 aba  ———>  #a#b#a#
 abba ———>  #a#b#b#a#

插入的是同樣的符號钙蒙,且符號不存在于原串,因此子串的回文性不受影響间驮,原來是回文的串躬厌,插完之后還是回文的,原來不是回文的竞帽,依然不是回文的烤咧。

B. 解決重復訪問的問題
我們把一個回文中最左或最右位置的字符與其對稱軸的距離稱為回文半徑。Manacher定義了一個回文半徑數(shù)組RL,用RL[i]表示以第i個字符為對稱軸的回文串的回文半徑抢呆。我們一般對字符串從左往右處理,因此這里定義RL[i]為第i個字符為對稱軸的回文串的最右一個字符與字符i距離笛谦。對于上面插入分隔符之后的兩個串抱虐,可以得到RL數(shù)組。

   s:    # a # b # a #
 RL :    1 2 1 4 1 2 1
RL-1:    0 1 0 3 0 1 0
  i :    0 1 2 3 4 5 6

   s:     # a # b # b # a #
 RL :     1 2 1 2 5 2 1 2 1
RL-1:     0 1 0 1 4 1 0 1 0
  i :     0 1 2 3 4 5 6 7 8

上面我們還求了一下RL[i]-1饥脑。通過觀察可以發(fā)現(xiàn)恳邀,RL[i]-1的值,正是在原來那個沒有插入過分割符的串中灶轰,以位置i為對稱軸的最長回文串的長度谣沸。那么只要我們求出RL數(shù)組,就能得到最長回文子串的長度笋颤。

那么問題就變成了乳附,怎樣高效地求RL數(shù)組,基本思路是利用回文串的對稱性伴澄,擴展回文串赋除。
我們再引入一個輔助變量MaxRight,表示當前訪問到的所有回文子串,所能觸及的最右一個字符的位置非凌。另外還要記錄下MaxRight對應的回文串的對稱軸所在位置,記為pos举农,它們的位置關系如下。

image.png

我們從左往右地訪問字符串來求RL,假設當前訪問到的位置是i,即要求RL[i],在對應上圖敞嗡,i必然在pos右邊颁糟,但是我們更關注的是,i是在MaxRight的左邊還是右邊喉悴,我們分情況分析棱貌。

  • ** 當i在MaxRight的左邊**
    如下圖所示:
image.png

我們知道,圖中兩個紅色塊之間(包括紅色塊)的串是回文的粥惧;并且以i對稱軸的回文串键畴,是與紅色塊間的回文串有所重疊的。我們找到i關于pos的對稱位置j,這個j對應RL[i]我們已經(jīng)算過的。根據(jù)回文串的對稱性起惕,以i為對稱軸的回文串和以j為對稱軸的回文串涡贱,有一部分是相同的。這里又有兩種細分情況惹想。

a. 以j為對稱軸的回文串比較短问词,短到如下圖所示:

image.png

這時我們知道RL[i]至少不會小于RL[j],并且已經(jīng)知道了部分的以i為中心的回文串,于是我們可以令RL[i]=RL[j].但是以i對稱軸的回文串可能實際上更長嘀粱,因此我們試著以i為對稱軸激挪,繼續(xù)向左右兩邊擴展,知道左右兩邊字符不同或者到達邊界锋叨。
b.以j為對稱軸的回文串很長垄分,如下圖所示:

image.png

這時,我們只能確定娃磺,兩條藍線之間的部分(及不超過MaxRight的部分)是回文的薄湿,于是從這個長度開始,嘗試以i為中心向左右兩邊擴展偷卧,知道左右兩邊字符不同或者到達邊界豺瘤。

綜上,我們只能獲取RL[2*pos - i]MaxRight-1這兩者中最小的值听诸,來保證該范圍內(nèi)的字符串是回文字符串坐求,RL[i] = min(RL[2*pos - i], MaxRight-1),之后都要嘗試更新MaxRightpos,因為有可能得到更大MaxRight.

具體操作如下:

step 1: 令RL[i]=min(RL[2*pos-i], MaxRight-i)
step 2: 以i為中心擴展回文串晌梨,直到左右兩邊字符不同桥嗤,或者到達邊界。
step 3: 更新MaxRight和pos
  • iMaxRight的右邊
    遇到這種情況派任,說明以i為對稱軸的回文串還沒有任何一部分被訪問過砸逊,于是只能從i的左右兩邊開始嘗試擴展了,當左右兩邊字符不同或者到達字符串邊界時停止更新掌逛。然后更新MaxRight和pos师逸。
    解法:

    string findLongestPalindrome3(string &s) {
    
          if (s.empty()) {
              return "";
          }
    
          if (s.size() == 1) {
              return s;
          }
    
          unsigned long length = s.size();
    
          int MaxRight = 0;
          int Maxlen = 0;
          int pos = 0;
          string tmpStr = s;
          for(int i = 0,k = 0; i <= length; i++){
              s.insert(k, "#");
              k = k + 2;
          }
          length = s.size();
    
          int *RL = new int[length]();
          memset(RL, 0x00, sizeof(length));
          for (int i = 0; i < length; i++) {
              if (i < MaxRight) {
                  RL[i] = min(RL[2*pos - i], MaxRight-1);
              }else {
                  RL[i] = 1;
              }
              while (i - RL[i] >= 0 && i+RL[i] < length && s[i - RL[i]] == s[i + RL[i]]) {
                  RL[i] += 1;
              }
              if (RL[i] + i - 1 > MaxRight) {
                  MaxRight = RL[i] + i - 1;
                  pos = i;
              }
              Maxlen = max(Maxlen, RL[i]);
          }
          if (Maxlen > 0) {
              return tmpStr.substr((pos+1)/2 - Maxlen/2, Maxlen - 1);
          }
          free(RL);
          return "";
      }
    

C語言解法:

/**
 找到 最長 回文 子串 (拉馬車 方法)
 
 @param string 字符串
 @param stringLength 字符串 長度
 */
void findLongestPalindromeThree(char *string, int stringLength) {
    if (string == NULL || stringLength == 0) {
        return;
    }
    if (stringLength == 1) {
        printf("%s\n", string);
        return;
    }

    // 插入 特殊字符 后字符串 長度
    int tmpStringLength = stringLength * 2 + 1;
    // 開辟 新的字符串
    char *tmpString = malloc(sizeof(char) * tmpStringLength);
    // 新字符串 復制 舊字符串 并在空隙插入 '#'
    tmpString[0] = '#';
    for (int tmpIndex = 0; tmpIndex < stringLength; tmpIndex ++) {
        tmpString[tmpIndex * 2 + 1] = string[tmpIndex];
        tmpString[tmpIndex * 2 + 2] = '#';
    }
    
    
    // 記錄 最長 半徑 范圍
    int maxRight = 0;
    // 記錄 最長 回文 字符串 長度
    int maxLength = 0;
    // 當前 最長 半徑 的 對稱軸
    int currentPosition = 0;
    // 記錄 每個 位置 最長回文 長度
    int *palindromeArray = malloc(sizeof(int) * tmpStringLength);
    memset(palindromeArray, 0x00, sizeof(tmpStringLength));
    
    // 遍歷 字符串
    for (int tmpIndex = 0; tmpIndex < tmpStringLength; tmpIndex++) {
        // 當前 字符 在最大 半徑 范圍 左邊
        if (tmpIndex < maxRight) {
            if (palindromeArray[2*currentPosition - tmpIndex] > maxRight - tmpIndex) {
                palindromeArray[tmpIndex] = maxRight - tmpIndex;
            }
            else {
                palindromeArray[tmpIndex] = palindromeArray[2*currentPosition - tmpIndex];
            }
        }
        // 當前 字符 在 最大半徑 范圍 右邊(沒有被遍歷過)
        else {
            palindromeArray[tmpIndex] = 1;
        }
        
        // 在先前 計算的 回文長度 基礎 上 擴展遍歷
        while (tmpIndex - palindromeArray[tmpIndex] >= 0 &&
               tmpIndex + palindromeArray[tmpIndex] < tmpStringLength &&
               tmpString[tmpIndex - palindromeArray[tmpIndex]] == tmpString[tmpIndex + palindromeArray[tmpIndex]]) {
            palindromeArray[tmpIndex] += 1;
        }
        
        if (palindromeArray[tmpIndex] + tmpIndex - 1 > maxRight) {
            maxRight = palindromeArray[tmpIndex] + tmpIndex - 1;
            currentPosition = tmpIndex;
        }
        
        // 更新 長度
        if (maxLength < palindromeArray[tmpIndex]) {
            maxLength = palindromeArray[tmpIndex];
        }
    }
    
    if (maxLength) {
        int tmpMaxLength = maxLength - 1;
        int tmpStartPostion = (currentPosition + 1)/2 - maxLength/2;
        
        for (int tmpIndex = 0; tmpIndex < tmpMaxLength; tmpIndex++) {
            printf("%c", string[tmpStartPostion]);
            tmpStartPostion++;
        }
        printf("\n");
    }
    
}

C.復雜度分析:

  • 空間復雜度:插入分隔符行程新串,占用了線性的空間大卸够臁篓像;RL數(shù)組也占用線性 大小的空間,因此空間復雜度是線性的皿伺。

  • 時間復雜度:盡管代碼里面有兩層循環(huán)员辩,由于內(nèi)層循環(huán)只是對尚未匹配的部分進行,因此對于每一個字符而言只會進行一次鸵鸥,因此時間復雜度是o(n).

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奠滑,一起剝皮案震驚了整個濱河市丹皱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宋税,老刑警劉巖摊崭,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異杰赛,居然都是意外死亡呢簸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門乏屯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來根时,“玉大人,你說我怎么就攤上這事辰晕「蛴” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵含友,是天一觀的道長忘苛。 經(jīng)常有香客問我,道長唱较,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任召川,我火速辦了婚禮南缓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘荧呐。我一直安慰自己汉形,他們只是感情好,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布倍阐。 她就那樣靜靜地躺著概疆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪峰搪。 梳的紋絲不亂的頭發(fā)上岔冀,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音概耻,去河邊找鬼使套。 笑死,一個胖子當著我的面吹牛鞠柄,可吹牛的內(nèi)容都是我干的侦高。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼厌杜,長吁一口氣:“原來是場噩夢啊……” “哼奉呛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤瞧壮,失蹤者是張志新(化名)和其女友劉穎登馒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體馁痴,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡谊娇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了罗晕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片济欢。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖小渊,靈堂內(nèi)的尸體忽然破棺而出法褥,到底是詐尸還是另有隱情,我是刑警寧澤酬屉,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布半等,位于F島的核電站,受9級特大地震影響呐萨,放射性物質(zhì)發(fā)生泄漏杀饵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一谬擦、第九天 我趴在偏房一處隱蔽的房頂上張望切距。 院中可真熱鬧,春花似錦惨远、人聲如沸谜悟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽葡幸。三九已至,卻和暖如春贺氓,著一層夾襖步出監(jiān)牢的瞬間蔚叨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工辙培, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缅叠,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓虏冻,卻偏偏與公主長得像肤粱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子厨相,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

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

  • 問題定義 最長回文子串問題:給定一個字符串领曼,求它的最長回文子串長度鸥鹉。 解法1:暴力解法 找到字符串的所有子串,判斷...
    HITMiner閱讀 661評論 0 2
  • 這次要記錄的是一個經(jīng)典的字符串的題目庶骄,也是一個經(jīng)典的馬拉車算法的實踐毁渗。相信在很多地方都會考到或者問到這道題目,這道...
    檸檬烏冬面閱讀 2,900評論 0 9
  • 最長回文串問題是一個經(jīng)典的算法題单刁。 0. 問題定義 最長回文子串問題:給定一個字符串灸异,求它的最長回文子串長度。如果...
    曾會玩閱讀 4,003評論 2 25
  • 問題:給定一個字符串羔飞,求它的最長回文子串長度肺樟。提示:如果一個字符串正著讀和反著讀是一樣的,那它就是回文串逻淌。下面是一...
    KevinHwong閱讀 498評論 0 0
  • 上一篇KMP算法之后好幾天都沒有更新么伯,今天介紹最長回文子串。 首先介紹一下什么叫回文串卡儒,就是正著讀和倒著讀的字符順...
    zero_sr閱讀 2,270評論 2 8