题目:最长回文子串

笔记 1#

使用的是“中心扩散法”

参考了这里的解法:https://leetcode.cn/problems/longest-palindromic-substring/solutions/2958179/mo-ban-on-manacher-suan-fa-pythonjavacgo-t6cx/

对于奇回文串,我们从最中间的一个元素开始向两边扩散,比如“bab”,第一次判断时 left = right,条件符合,所以 left–, right++;然后进入第二次判断,此时两者指向的字符都是‘b’,条件依然满足….直到左右指针指向的字符不同时,计算当前字符串长度

对于偶回文串,还是从中间开始扩散,只不过这次需要选取两个元素

为了将两种情况合并处理,可以将 i 的最大范围改为 2n - 1,因为

  • 奇数长度回文中心:每个字符本身就是一个中心 → n 个
  • 偶数长度回文中心:每两个相邻字符之间是一个中心 → n - 1 个

两者相加,所有回文中心的数量就是 2n - 1 个

longestPalindrome()

 1string longestPalindrome(string s)
 2{
 3    int left = 0, right = 0;
 4    int n = s.size();
 5    for(int i = 0; i < 2 * n - 1; i++)
 6    {
 7        int l = i / 2, r = (i + 1) / 2;
 8        while(0 <= l && r < n && s[l] == s[r])
 9        {
10            l--;
11            r++;
12        }
13        if(r - l - 1 > right - left)
14        {
15            right = r;
16            left = l + 1;
17        }
18    }
19    return s.substr(left, right - left);
20}

来源:语雀原笔记

笔记 2#

以一个字符(奇数回文串)或两个字符中间的空隙(偶数回文串)为中心,向左右两端扩散,如果两端字符相同,则继续扩展,并记录当前字符串的起始点

longestPalindrome()

 1std::pair<int, int> ExpandAroundCenter(const string& s, int left, int right)
 2{
 3    while(left >= 0 && right < s.size() && s[left] == s[right])
 4    {
 5        --left;
 6        ++right;
 7    }
 8    return {left+1, right-1};
 9}
10string longestPalindrome(string s)
11{
12    int left = 0, right = 0;
13    // 如果输入字符串总长为1,则直接返回该字符串
14    if(s.size() < 2)
15        return s;
16    for(int i = 0; i < s.size(); ++i)
17    {
18        // 奇数回文串
19        auto [left1, right1] = ExpandAroundCenter(s, i, i);
20        // 偶数回文串
21        auto [left2, right2] = ExpandAroundCenter(s, i, i+1);
22        // 判断是奇数还是偶数
23        if(right1 - left1 > right - left)
24        {
25            left = left1;
26            right = right1;
27        }
28        if(right2 - left2 > right - left)
29        {
30            left = left2;
31            right = right2;
32        }
33    }
34    // substr(start,length):提取特定字符串
35    return s.substr(left, right-left+1);
36}

来源:语雀原笔记