【前端面试常见算法题系列】5. 最长回文子串

167 阅读2分钟

“Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。”

一、题目描述

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

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

提示:

  • 1 <= s.length <= 1000
  • s 仅由数字和英文字母组成

二、思路分析

所谓回文数就是指 正序(从左往右)和反序(从右往左)读都是同一样的整数。字符串也是同样的道理。

而寻找回文串的核心思想就是:从字符串中间向两端扩展来判断回文串。

题目要求我们返回最长的回文串,因此我们需要从字符串开头一直遍历到字符串结尾,需要注意的是:我们不知道开始遍历的这个中心是一个字符还是两个字符,因此我们干脆进行两次递归,一次是以一个字符为中心递归扩展,一次是以两个字符为中心递归扩展,总共进行两次递归,每次递归结束后更新最长字符串,直到遍历到字符串末尾。

需要注意的是:以两个字符为中心需要判断这两个字符是否相同,不然无论如何扩展,都不可能是回文串。

以示例2举例子:s = "cbbd"

  • 我们定义一个结果字符串 res ,开始遍历字符串 s
  • 首先我们以 c 为中点向左右两边扩展,因为左边是边界无法扩展下去,因此直接 return 这个中点 ,也就是 c;以 cb 为中点向两边扩展,因为 c!==b ,返回空字符串即可,然后也退出递归。两次递归结束后,更新最长回文字符串。于是继续遍历。
  • b 为中点左右扩展,每次扩展的步长为 1 ,因此现在扩展的区间范围为 3 (加上原本的中点),现在判断扩展的区间范围内 除中点外的字符 是否左右一一对称,如果是则继续扩展区间,如果不是则返回回退(左右都得回退)后的扩展区间范围内的字符,这里返回 b;然后接着以 bb 为中点开始扩展,判断两个字符是否相等,是则扩展区间范围,不是则返回回退(左右都得回退)后的扩展区间范围内的字符,这里返回 bb。两次递归结束后,更新最长回文字符串。然后继续遍历。
  • ...
  • 遍历结束后,最长的回文子串就出来了。

三、AC 代码

class Solution {
public:
    string longestPalindrome(string s) {
        string res = "";
        for (int i = 0; i < s.size(); i++) {
            // 以 s[i] 为中心的最长回文子串
            string s1 = palindrome(s, i, i);
            // 以 s[i] 和 s[i+1] 为中心的最长回文子串
            string s2 = palindrome(s, i, i + 1);
            res = res.size() > s1.size() ? res : s1;
            res = res.size() > s2.size() ? res : s2;
        }
        return res;
    }
    string palindrome(string s, int left, int right) {
        // 防止索引越界,同时判断回文
        while (left >= 0 && right < s.size() && s[left] == s[right]) {
            left--;
            right++;
        }
        return s.substr(left + 1, right - left - 1);
    }
};