“Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。”
一、题目描述
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
提示:
1 <= s.length <= 1000s仅由数字和英文字母组成
二、思路分析
所谓回文数就是指 正序(从左往右)和反序(从右往左)读都是同一样的整数。字符串也是同样的道理。
而寻找回文串的核心思想就是:从字符串中间向两端扩展来判断回文串。
题目要求我们返回最长的回文子串,因此我们需要从字符串开头一直遍历到字符串结尾,需要注意的是:我们不知道开始遍历的这个中心是一个字符还是两个字符,因此我们干脆进行两次递归,一次是以一个字符为中心递归扩展,一次是以两个字符为中心递归扩展,总共进行两次递归,每次递归结束后更新最长字符串,直到遍历到字符串末尾。
需要注意的是:以两个字符为中心需要判断这两个字符是否相同,不然无论如何扩展,都不可能是回文串。
以示例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);
}
};