hiho一下第一周#1032 : 最长回文子串

一个字符串中连续的一段就是这个字符串的子串,而回文串指的是12421这种从前往后读和从后往前读一模一样的字符串,所以最长回文子串的意思就是这个字符串中最长的身为回文串的子串

思路1

以字符串中的每个字符为中心,向左右两边寻找,直到找到最长的回文子串

int longestHuiWen(string &p) {
    p = '$' + p;
    int ans = 0;
    for (int i = 1; p[i]; ++i) {
        int start = i, end = i;
        while (p[end + 1] == p[i])  ++end;  //跳过相同字符
        i = end;
        while (p[end + 1] == p[start - 1])  ++end, --start;
        ans = max(ans, end-start+1);
    }
    return ans;
}

思路2

考虑大回文中包含着小回文,下图id为回文中心,mx为回文边界。f[id]为回文串向左右扩张的长度,则有mx = id+f[id]

  • i < mx时
    • 情况1,小回文大回文内,mx-i > f[j],则f[i]=f[j]。
      hiho一下第一周#1032 : 最长回文子串_第1张图片
    • 情况2,小回文超出大回文范围,mx-i <= f[j],则至少绿色框内是匹配的,超出边界的需要去尝试
      hiho一下第一周#1032 : 最长回文子串_第2张图片
    • 综上可以得出结论f[i] >= min(f[2*id-i], mx-i)
  • i >= mx时,无法做出更多假设,f[i] = 1。

为保证字符串在奇数偶数下都能正常工作,我们在字符串中插入’#’,如$#a#b#a#b#a#b#a#,对此字符串我们得出一个有趣的结论,f[id]-1即为以id为轴的最大回文串长度。

int Manacher(string &p) {
    string s;
    s += "$#";
    int n = 2;
    for (int i = 0; p[i]; ++i, n += 2)  s += p[i],  s += '#';
    int maxRight = 1, j = 0;
    for (int i = 1; i < n; ++i) {
        if (maxRight > i) {
            f[i] = min(maxRight - i, f[2 * j - i]);
        }else {
            f[i] = 1;
        }
        while (s[i + f[i]] == s[i - f[i]])  f[i]++;
        if (f[i] + i > maxRight) {
            maxRight = f[i] + i;
            j = i;
        }
    }
    int ans = 0;
    for (int i = 0; i < n; ++i) ans = max(ans, f[i] - 1);
    return ans;
}

你可能感兴趣的:(hiho)