第 443 场周赛——子字符串连接后的最长回文串 II

题目

子字符串连接后的最长回文串 II

题解

我们选中s中字串x,t中字串y,会出现三种情况:
1.\(\left| x \right|\) = \(\left| y \right|\) , 这类似最长公共子串问题,这里使用的代码没有将t翻转,i进行了偏移操作减少了i = 0特判的情况。最终结果为f[i][j]的最大值的两倍。
2.\(\left| x \right|\) > \(\left| y \right|\) , 这意味着x的长为\(\left| x \right|\) - \(\left| y \right|\)后缀是一个回文串,只要找出回文串,然后找到以回文串左边界-1结尾的字串与t字串的最长公共字串,遍历所有的回文串,最终答案是回文串的长度加上两倍的以左边界-1结尾的字串与t字串的最长公共字串的长度。回文子串用中心扩展法进行查找。
3.\(\left| x \right|\) < \(\left| y \right|\) , 意味着中间的回文串在y中,我们可以翻转y串和x串,就可以回到第二种情况进行计算。
复杂度分析
时间复杂度:O(nm+n2+m2),其中 n 是 s 的长度,m 是 t 的长度。
空间复杂度:O(n2+m2)。用滚动数组可以优化至 O(n+m)。

参考代码

class Solution {
    int calc(string& s, string& t){
        int n = s.size(), m = t.size();
        vector<int> mx(n + 1);
        vector f(n + 1, vector<int> (m + 1));
        for(int i = 0; i < n; i ++){
            for(int j = 0; j < m; j ++){
                if(s[i] == t[j]){
                    f[i + 1][j] = f[i][j + 1] + 1;
                }
            }
            mx[i + 1] = ranges::max(f[i + 1]);
        }
        int ans = ranges::max(mx) * 2;
        
        for(int i = 0; i < 2 * n - 1; i ++){
            int l = i / 2, r = (i + 1) / 2;
            while(l >= 0 && r < n && s[l] == s[r]){
                l --;
                r ++;
            }
            if(l + 1 <= r - 1){
                ans = max(ans, r - l - 1 + mx[l + 1] * 2);
            }    
        }
        return ans;
    }
public:
    int longestPalindrome(string s, string t) {
        string rev_s = s, rev_t = t;
        ranges::reverse(rev_s);
        ranges::reverse(rev_t);
        return max(calc(s, t), calc(rev_t, rev_s));
    }
};
posted @ 2025-03-31 15:47  PZnwbh  阅读(44)  评论(0)    收藏  举报