Leetcode第5題: 最長(zhǎng)回文子串

一、題目來(lái)源:leetcode第5題

二、題目描述

給你一個(gè)字符串 s毅弧,找到 s 中最長(zhǎng)的回文子串擅羞。

如果字符串的反序與原始字符串相同,則該字符串稱為回文字符串。

示例 1:

輸入: s = "babad" 輸出: "bab" 解釋: "aba" 同樣是符合題意的答案躁锁。

示例 2:

輸入: s = "cbbd" 輸出: "bb"

提示:

  • 1 <= s.length <= 1000
  • s 僅由數(shù)字和英文字母組成

三、解題

3.1 解法一

  1. 思路

    定義兩個(gè)指針卵史,使用中心擴(kuò)展法來(lái)找到回文子串战转。遍歷字符串中的每個(gè)字符,以當(dāng)前字符為中心向兩邊擴(kuò)展以躯,分別檢查奇數(shù)長(zhǎng)度和偶數(shù)長(zhǎng)度的回文子串槐秧。

  1. 解法

/**
 * 在給定的字符串中找到最長(zhǎng)的回文子串。
 *
 * @param {string} s - 輸入字符串忧设。
 * @return {string} - 找到的最長(zhǎng)回文子串刁标。
 */
const longestPalindrome = function(s) {
  let res = '';

  for (let i = 0; i < s.length; i++) {
    const odd = expandAroundCenter(s, i, i);
    const even = expandAroundCenter(s, i, i + 1);
    const longest = odd.length > even.length ? odd : even;
    if (longest.length > res.length) {
      res = longest;
    }
  }
  return res;

  /**
   * 在給定的字符串中找到最長(zhǎng)的回文子串。
   *
   * @param {string} s - 輸入字符串址晕。
   * @param {number} l - 要檢查的子串的左索引膀懈。
   * @param {number} r - 要檢查的子串的右索引。
   * @return {string} - 找到的最長(zhǎng)回文子串谨垃。
 */
  function expandAroundCenter(s, l, r) {
    while (l >= 0 && r < s.length && s[l] === s[r]) {
      l--;
      r++;
    }
    return s.substring(l + 1, r);
  }
};
  1. 時(shí)間復(fù)雜度

由于遍歷字符串需要 O(n) 的時(shí)間启搂,而在每個(gè)位置上進(jìn)行中心擴(kuò)展需要 O(n) 的時(shí)間硼控,因此總體時(shí)間復(fù)雜度為 O(n^2)

  1. 空間復(fù)雜度

算法只使用了常數(shù)個(gè)變量來(lái)保存中間結(jié)果胳赌,沒有使用額外的數(shù)據(jù)結(jié)構(gòu)或數(shù)組牢撼。因此,空間復(fù)雜度可以表示為O(1) 疑苫。

3.2 解法二

  1. 思路

馬拉車算法(Manacher's Algorithm)熏版,基本思想是利用回文串的對(duì)稱性來(lái)減少不必要的重復(fù)計(jì)算。它通過(guò)維護(hù)一個(gè)回文半徑數(shù)組捍掺,以及一個(gè)當(dāng)前已知的最右回文邊界纳决,來(lái)快速計(jì)算每個(gè)字符位置的回文半徑。該算法的具體實(shí)現(xiàn)比較復(fù)雜乡小,但可以在線性時(shí)間內(nèi)找到最長(zhǎng)回文子串阔加。

  1. 解法

/**
 * 在給定的字符串中找到最長(zhǎng)的回文子串。
 *
 * @param {string} s - 輸入字符串满钟。
 * @return {string} - 找到的最長(zhǎng)回文子串胜榔。
 */
const longestPalindrome = function(s) {
  // 預(yù)處理字符串,在每個(gè)字符之間插入特殊字符
  const preprocessString = function(s) {
    let result = '^';
    for (let i = 0; i < s.length; i++) {
      result += '#' + s.charAt(i);
    }
    result += '#$';
    return result;
  };
  // 預(yù)處理字符串
  const processedString = preprocessString(s);
  const n = processedString.length;
  const palindromeRadius = new Array(n).fill(0); // 回文半徑數(shù)組
  let center = 0; // 當(dāng)前已知的最右邊回文子串的中心
  let right = 0; // 當(dāng)前已知的最右邊回文子串的右邊界

  for (let i = 1; i < n - 1; i++) {
    // 利用對(duì)稱性得到一部分回文信息
    if (i < right) {
      const mirror = 2 * center - i;
      palindromeRadius[i] = Math.min(right - i, palindromeRadius[mirror]);
    }

    // 中心擴(kuò)展法檢查以當(dāng)前字符為中心的回文子串
    while (
      processedString[i + 1 + palindromeRadius[i]] ===
      processedString[i - 1 - palindromeRadius[i]]
    ) {
      palindromeRadius[i]++;
    }

    // 更新最右邊回文子串的中心和右邊界
    if (i + palindromeRadius[i] > right) {
      center = i;
      right = i + palindromeRadius[i];
    }
  }

  // 找到最長(zhǎng)回文子串的中心位置和長(zhǎng)度
  let maxRadius = 0;
  let centerIndex = 0;
  for (let i = 1; i < n - 1; i++) {
    if (palindromeRadius[i] > maxRadius) {
      maxRadius = palindromeRadius[i];
      centerIndex = i;
    }
  }

  // 根據(jù)中心位置和長(zhǎng)度獲取原始字符串中的最長(zhǎng)回文子串
  const start = (centerIndex - maxRadius) / 2;
  const end = start + maxRadius;
  return s.substring(start, end);
};
  1. 時(shí)間復(fù)雜度

    1. 預(yù)處理字符串的時(shí)間復(fù)雜度為 O(n)湃番,其中 n 是字符串的長(zhǎng)度夭织。在預(yù)處理過(guò)程中,我們?cè)诿總€(gè)字符之間插入特殊字符(通常是#)吠撮,以處理偶數(shù)長(zhǎng)度的回文子串尊惰。

    2. 馬拉車算法的主要部分是一個(gè)線性的循環(huán),遍歷預(yù)處理后的字符串泥兰。在該循環(huán)中弄屡,我們使用對(duì)稱性和中心擴(kuò)展法來(lái)計(jì)算每個(gè)字符作為回文子串中心時(shí)的回文半徑。

      1. 對(duì)稱性的計(jì)算時(shí)間復(fù)雜度為 O(n)鞋诗。我們維護(hù)兩個(gè)變量 centerright膀捷,并利用已知回文子串的對(duì)稱性來(lái)更新回文半徑。
      2. 中心擴(kuò)展法的時(shí)間復(fù)雜度為 O(n)削彬。我們?cè)诿總€(gè)字符為中心時(shí)全庸,向左右兩側(cè)擴(kuò)展并檢查回文性質(zhì)。
    3. 因此融痛,整個(gè)算法的時(shí)間復(fù)雜度為 O(n) 壶笼。

  1. 空間復(fù)雜度

    1. 預(yù)處理后的字符串需要 O(n) 的額外空間,因?yàn)槲覀冊(cè)诿總€(gè)字符之間插入特殊字符雁刷。
    2. 回文半徑數(shù)組需要 O(n) 的額外空間覆劈,用于存儲(chǔ)每個(gè)字符作為回文子串中心時(shí)的回文半徑。
    3. 因此,總體空間復(fù)雜度為 O(n) 墩崩。

四氓英、知識(shí)點(diǎn)

雙指針?biāo)惴?/strong>是一種常用的技巧,在解決多種問題時(shí)都可以應(yīng)用鹦筹。雙指針的使用方式分以下3種:

  1. 快慢指針:快慢指針是一種特殊的雙指針技巧铝阐,其中一個(gè)指針(快指針)移動(dòng)的速度比另一個(gè)指針(慢指針)快。這種技巧常用于鏈表相關(guān)的問題铐拐,例如判斷鏈表是否有環(huán)徘键、找到鏈表的中間節(jié)點(diǎn)等”轶快慢指針可以根據(jù)問題的要求靈活調(diào)整速度和距離吹害。
  2. 同向 雙指針:同向雙指針是指兩個(gè)指針都向同一個(gè)方向移動(dòng)。通常虚青,兩個(gè)指針的起始位置相同它呀,然后逐步向右或向左移動(dòng)。這種雙指針移動(dòng)方式常用于數(shù)組或字符串的搜索問題棒厘,例如在有序數(shù)組中查找兩個(gè)數(shù)的和纵穿、找到滿足特定條件的子數(shù)組等。
  3. 相向 雙指針:相向雙指針是指兩個(gè)指針分別從兩個(gè)不同的方向移動(dòng)奢人,通常是從數(shù)組或字符串的兩端開始谓媒。這種雙指針移動(dòng)方式常用于有序數(shù)組或字符串的搜索問題,例如找到兩個(gè)有序數(shù)組的公共元素何乎、判斷一個(gè)字符串是否為回文串等句惯。相向雙指針可以逐步縮小搜索范圍,從而提高算法的效率支救。

雙指針?biāo)惴ㄟm用于解決許多問題抢野,包括但不限于以下情況:

  1. 數(shù)組或字符串的搜索:當(dāng)要在數(shù)組或字符串中查找特定元素或滿足特定條件的子數(shù)組/子串時(shí),可以使用雙指針?biāo)惴蕖@缑杀#行驍?shù)組的兩數(shù)之和、三數(shù)之和等問題欲主。
  2. 數(shù)組或字符串的反轉(zhuǎn)或交換:使用雙指針可以實(shí)現(xiàn)對(duì)數(shù)組或字符串的反轉(zhuǎn)或交換操作。例如逝嚎,反轉(zhuǎn)字符串扁瓢、顛倒鏈表等問題。
  3. 回文問題:判斷一個(gè)字符串或子串是否是回文补君,或者找到最長(zhǎng)回文子串時(shí)引几,雙指針?biāo)惴ㄊ且环N常用的解決方案。例如,驗(yàn)證回文串伟桅、最長(zhǎng)回文子串等問題敞掘。
  4. 快慢指針:在鏈表相關(guān)問題中,使用快慢指針可以判斷是否存在環(huán)楣铁、找到鏈表的中間節(jié)點(diǎn)等玖雁。快慢指針是雙指針?biāo)惴ǖ囊环N特殊形式盖腕。
  5. 歸并排序:歸并排序中的合并操作可以使用雙指針來(lái)實(shí)現(xiàn)赫冬。通過(guò)將兩個(gè)有序數(shù)組合并為一個(gè)有序數(shù)組,雙指針可以高效地完成歸并排序溃列。
  6. 滑動(dòng)窗口:滑動(dòng)窗口是一種常見的算法技巧劲厌,用于處理數(shù)組或字符串的連續(xù)子序列問題。通過(guò)使用兩個(gè)指針來(lái)維護(hù)窗口的起始位置和結(jié)束位置听隐,可以高效地解決滑動(dòng)窗口相關(guān)的問題补鼻。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市雅任,隨后出現(xiàn)的幾起案子风范,更是在濱河造成了極大的恐慌,老刑警劉巖椿访,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乌企,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡成玫,警方通過(guò)查閱死者的電腦和手機(jī)加酵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)哭当,“玉大人猪腕,你說(shuō)我怎么就攤上這事∏湛保” “怎么了陋葡?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)彻采。 經(jīng)常有香客問我腐缤,道長(zhǎng),這世上最難降的妖魔是什么肛响? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任岭粤,我火速辦了婚禮,結(jié)果婚禮上特笋,老公的妹妹穿的比我還像新娘剃浇。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布虎囚。 她就那樣靜靜地躺著角塑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪淘讥。 梳的紋絲不亂的頭發(fā)上圃伶,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音适揉,去河邊找鬼留攒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嫉嘀,可吹牛的內(nèi)容都是我干的炼邀。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼剪侮,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拭宁!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起瓣俯,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤杰标,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后彩匕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腔剂,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年驼仪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了掸犬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绪爸,死狀恐怖湾碎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情奠货,我是刑警寧澤介褥,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站递惋,受9級(jí)特大地震影響柔滔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜萍虽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一廊遍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贩挣,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至绒净,卻和暖如春见咒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挂疆。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工改览, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缤言。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓宝当,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親胆萧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子庆揩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

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