回文子串

原题在这里

  概述题意,问给定字符串s中有多少个子串是回文串,不同下标构成的子串视为不同子串。

analyse:

  1.暴力,数据范围只有1e3,substr+reverse暴力判断

code:

class Solution
{
    bool check(string s)
    {
        string x = s;
        reverse(x.begin(), x.end());
        return x == s;
    }

public:
    int countSubstrings(string s)
    {
        /*
            analyse:
                尝试翻译为KMP:
                    末位跳转次数+len?
                len<=1000
                x
                肯定是有数据结构的规律的,但是这里就写暴力了
        */
        int ans = 0;
        for (int i = 0; i < s.length(); ++i)
            for (int j = s.length() - i; j > 0; --j)
                ans += check(s.substr(i, j));
        return ans;
    }
};
easy

  2.中心拓展,但不是想当然式的两边+1+1那种,考虑中心的奇偶性,分为两种判断:

code:

class Solution
{
    int ans = 0;
    int count(string s, int l, int r)
    {
        int num = 0;
        while (l >= 0 && r < s.length() && s[l] == s[r])
            ++num, --l, ++r;
        return num;
    }

public:
    int countSubstrings(string s)
    {
        for (int i = 0; i < s.length(); ++i)
            ans += count(s, i, i) + count(s, i, i + 1);
        return ans;
    }
};
mid

  3.manacher,也属于是中心拓展,但是manacher会利用前面判断对后序判断进行优化,等于是中心拓展的优化。

关键点在于:对于manacher的中心数组p的使用,p[i]表示以i为中心的最长回文串半径,那么对于有多少个回文子串即为sum(p[i]/2)即可,因为p所处理的字符串为预处理过的字符串,所以单个字符构成的字符串并不计入在内。

code:

class Solution
{
    string S;
    void Init(string s)
    {
        S = "~#";
        for (char i : s)
            S += i, S += '#';
    }
    int manacher(string s)
    {
        int mx = 0, id = 0, l = s.length();
        int ans = 0;
        // mx最大右端点,id最长回文串中心点
        vector<int> p(l);
        for (int i = 1; i < l; ++i)
        {
            if (mx > i)
                p[i] = min(mx - i, p[id - (i - id)]);
            else
                p[i] = 1;
            while (s[i - p[i]] == s[i + p[i]])
                ++p[i];
            if (p[i] + i > mx)
            {
                mx = p[i] + i;
                id = i;
            }
            ans += p[i] / 2;
        }
        return ans;
    }

public:
    int countSubstrings(string s)
    {
        /*
        analyse:
            翻译为manacher:
                p[i]表示以i为中心的最长回文串半径长度,那么最终ans=sum(p[i]/2)
        */
        Init(s);
        return manacher(S);
    }
};

 

【Over】

posted @ 2022-05-06 09:31  Renhr  阅读(126)  评论(0)    收藏  举报