leetcode647(テキスト文字列を返す:管理アルゴリズム)

文字列sが与えられた場合、あなたの仕事は、この文字列に含まれる回文の部分文字列の数を数えることです。
開始位置または終了位置が異なる部分文字列は、同じ文字で構成されていても、異なる部分文字列と見なされます。

例:
入力:入力: "bbb"
出力:6
説明:6つの回文サブストリング: "b"、 "b"、 "b"、 "bb"、 "bb"、 "bbb"

問題の解決策(1):動的プログラミング、動的プログラミング関数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;
    }
}

問題の解決策(2):文字列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;
    }
}

問題解決(3):管理者アルゴリズム

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<edge),则Math.min(r[2*center-i],edge-i)一定在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;

    }
}

おすすめ

転載: blog.csdn.net/CY2333333/article/details/108120251