leetcode647(回文字串:manacher算法)

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

例:
输入:输入:“bbb”
输出:6
解释:6个回文子串: “b”, “b”, “b”, “bb”, “bb”, “bbb”

题解(一):动态规划,构造动态规划函数 F(x,y)记录字符串s第x-1个字符到第y-1个构成的子字符串是否为回文字符串。进行动态规划时,通过遍历字符串s,从找长度为1的回文子串开始,逐次增长回文字串长度进行回文字符串的判断。

class Solution {
    public int countSubstrings(String s) {
           int res=0;
           int len=s.length();
           boolean[][]dp=new boolean[len][len];
           for(int i=0;i<len;i++)
               for(int k=0;k+i<len;k++){
                   if(i==0) {
                       dp[k][k + i] = true;
                       res++;
                   }
                   else{
                       if(s.charAt(k)==s.charAt(k+i)){
                           if(i==1||dp[k+1][k+i-1]) {
                               dp[k][k + i] = true;
                               res++;
                           }
                       }
                   }
               }
           return res;
    }
}

题解(二):遍历字符串s,将每一个字符都作为回文字符串的中心,向两侧扩展,统计回文字符子串个数。

class Solution {
    public int countSubstrings(String s) {
         int res=0;
         int left,right;
         for(int i=0;i<s.length();i++) {
             for (int k = 0; k < 2; k++) {
                 left=i;
                 right=i+k;
                 while (left >= 0 && right < s.length()) {
                           if(s.charAt(left)==s.charAt(right)) {
                               res++;
                               left--;
                               right++;
                           }
                           else 
                               break;
                 }
             }
         }
         return res;
    }
}

题解(三):manacher算法

class Solution {
    public int countSubstrings(String s) {
        int res=0;
        /*
        * 填充字符串,在两个字符串的中间和两端填充‘#’,使得字符串的长度为奇数
        * 在字符串新的两端填充‘$’、‘!’、防止越界问题
        * 遍历新字符串,以新字符串的每个字符为中心,向外扩展,记录回文字符串的最大半径
        * 设单个字符为中心的回文串最大半径为r,则恢复到原字符串后,还剩下的有效回文字符串个数为r/2
        * 例:d#b#a#b#c,以a为中心,r=4,恢复为原字符串后(dbabc),有效回文字符串个数是(int)4/2=2
        *    #b#b#,以第二个‘#’为中心,r=3,恢复后(bb),有效回文字符串个数是(int)3/2=1
        */
        StringBuffer string=new StringBuffer("$#");
        for(int i=0;i<s.length();i++){
            string.append(s.charAt(i)+"#");
        }
        string.append("!");
        int len=string.length();
        int[]r=new int[string.length()];
        int center=0;
        int rMax=1;
        /*
        * 我们用int[]r保存s中以每个字符为中心的最大回文字符串半径
        * manacher算法中,我们要维护一个当前的最大回文半径rMax,和这个最大回文半径
        * 所对应的回文中心center,以及最大边界(edge=center+rMax-1),如果当前的字符串中心k在
        * 最大边界内(k
        for(int i=1;i<len-1;i++){
            if(i>center+rMax-1)
                r[i]=1;
            else{
                r[i]=Math.min(r[2*center-i],rMax+center-i);
            }
            while(string.charAt(i-r[i])==string.charAt(i+r[i]))
                r[i]++;
            if(r[i]>rMax||i>center+rMax){
                center=i;
                rMax=r[i];
            }

            res+=r[i]/2;
        }
        return res;

    }
}

你可能感兴趣的:(每天一道算法题)