leetcode-7:回文串问题

回文串问题

解释一下为什么会记录刷题过程。记得研一为了算法课刷题,曾经在本子中记录过思路和代码。这些算法思想,平常也没机会使用,长时间不用,忘得比较快,再加上本子不易保存和现在电子阅读的普及,所以就导致复习不好复习,还得从头再来,所以这次刷题就记录下来,发在csdn和知乎,以便随时观看。

最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

思路: 最长回文子串问题的解决方法有常见的 O ( n 2 ) O\left(n^{2}\right) O(n2),还有神奇的 O ( n ) O\left(n\right) O(n),被称为马拉车算法。对于 O ( n 2 ) O\left(n^{2}\right) O(n2)算法,是考虑到回文串的对称性,每次循环选择一个中心,左右扩展,直到左右字符不再相等。考虑到字符串长度的奇偶性,为了全面寻找最长回文串,需要从一个字符开始扩展,或者从两个字符间开始扩建,有2n-1个中心点。

class Solution {
public:
    string longestPalindrome(string s) {
        int len = s.length();
        if(len==0) return "";
        int left=0, right=0;
        for(int i=0;i len_2 ? len_1 : len_2;
            if((right - left) < len){
                left = i - (len - 1) / 2;
                right = i + len / 2;
            }
        }
        return s.substr(left, (right - left + 1));
    }
    int expand(string s, int left, int right){
        while(left>=0&&right

马拉车算法(Manacher’s Algorithm)

马拉车算法将时间复杂度降到了 O ( n ) O\left(n\right) O(n),但是空间复杂度为 O ( n ) O\left(n\right) O(n)。上述的中心扩展法的空间复杂度为 O ( 1 ) O\left(1\right) O(1),用空间换取时间。

中心扩展的时候需要考虑到字符串奇偶性,假设字符串长度为 n n n,通过加入 n + 1 n+1 n+1个分隔符使得字符串长度为奇数 2 n + 1 2n+1 2n+1,将“babad”处理成“#b#a#b#a#d#"。

设置目前回文串的对称中心点为Center,回文半径长度为Radius,右边到达最远为Right=Center+Radius,当前点为 i i i i i i关于Center的对称点为 i _ m i r r o r = 2 ∗ C e n t e r − i i\_mirror = 2 *Center - i i_mirror=2Centeri。记录每个点回文字符串半径的矩阵为 P P P

我们需要根据i和Right的大小来计算 P [ i _ m i r r o r ] P[i\_mirror] P[i_mirror]

  • i < R i g h t i < Right i<Right时,如果 i + P [ i _ m i r r o r ] > = R i + P[i\_mirror] >= R i+P[i_mirror]>=R,那么可以根据回文串对称性得到 P [ i ] = P [ i _ m i r r o r ] P[i] = P[i\_mirror] P[i]=P[i_mirror];否则,超越界限,所以需要取 m i n ( P [ i _ m i r r o r ] , R − i ) min(P[i\_mirror], R-i) min(P[i_mirror],Ri),然后再左右扩展

  • 如果 i > R i > R i>R,此时镜像预测不起作用, P [ i ] = 0 P[i] = 0 P[i]=0,需左右扩展。

class Solution {
public:
    string pre_process(string s){
        int len = s.length();
        len = 2 * len + 1;
        string str="";
        for(int i=0;i P(len, 0);
        int c = 0, r = 0;
        int max_length = INT_MIN;
        int max_index = 0;
        for(int i=0;ii){
                P[i] = min(r-i, P[i_mirror]);
            }
            while(((i+P[i])=0)&&str[i+P[i]]==str[i-P[i]]){
                P[i]++;
            }
            if((i+P[i]) > r){
                c = i;
                r = i+P[i];
            }
            if(max_length < P[i]){
                max_index= i;
                max_length = P[i];
            }
        }
        return s.substr((max_index - max_length + 1)/2, max_length-1);
    }
};

回文子串

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。

思路: 简单暴力,我们搜索每一个中心点。假设字符串长度为 n n n,按照扩展算法的描述,有 2 ∗ n + 1 2*n+1 2n+1中心,对每一中心进行扩展,如果是回文串,则记录下来。

class Solution {
public:
    int countSubstrings(string s) {
        int len = s.length();
        len = len*2-1;
        int left=0,right=0;
        int num = 0;
        for(int i=0;i=0&&right

你可能感兴趣的:(leetcode-7:回文串问题)