1. 程式人生 > >leetcode-中級演算法-陣列和字串-最長迴文字串

leetcode-中級演算法-陣列和字串-最長迴文字串

給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。

示例 1:
輸入: “babad”
輸出: “bab”
注意: "aba"也是一個有效答案。

示例 2:
輸入: “cbbd”
輸出: “bb”


思路

這道題很顯然可以用暴力求解,但時間複雜度太高,也起不到刷題的訓練作用。搜了一下,全是關於manacher的演算法。看了好久才弄懂的。寫這篇也是來鞏固梳理一下(其他人寫的好多程式碼很難懂!)希望讀者有耐心讀完!

理論

迴文可能是奇數:‘aba’;也可能是偶數:‘abba’,最節省時間的判斷迴文方法是從中間開始向兩邊判斷,但偶數個數的迴文字串就不行了。於是——Manacher就想到,在所有字元中間新增一個佔位的符號(例如’#’,必須不是原始字串中的字元),這樣 ‘abba’ 就變為 ‘#a#b#b#a#’,就可以從中間的 ‘#’ 開始想兩邊延申啦。

所以,第一步就是將原始字串 'abba' 變化為含有 '#' 的字串 '#a#b#b#a#'
s = '#' + s.split('').join('#') + '#';

接下來,就要迴圈遍歷了。以每個字元為中心,向兩邊延申直到不相等,延申長度為 radius,

第二步,設定變數:
let radius = 0;

還要設定一個最大半徑,用來儲存迴文的最大半徑,和儲存最長子串的subString

let maxRadius = 0;
let subString = '';

當radius大於maxRadius時,說明該更新了,同時,要儲存最長子串 subString

subString = s.slice(i - radius + 1, i + radius);

遍歷完後,別忘了把子串中的所有’#’ 去掉

while (subString.includes('#')) {
    subString = subString.replace('#', '')
}

全部程式碼:

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function(s) {
  s = '#' + s.split('').join('#') + '#';
  let radius = 0;
  let maxRadius = 0;
  let subString = '';
  
  for (let i = 0; i < s.length ; i ++) {
    radius = 1
    
    while (s[i - radius] === s[i + radius] && s[i - radius] !== undefined) {
      radius ++;
    }
    
    if (radius > maxRadius) {
      subString = s.slice(i - radius + 1, i + radius);
      maxRadius = radius;
    }
    
  }
  
  while (subString.includes('#')) {
    subString = subString.replace('#', '')
  }
  
  return subString;
};

PS:這是簡單精簡版!也能通過測試,原版的更加優化快速,但我已無力!