最长回文子串 最长回文子序列

1.最长回文子序列(可以不连续)

#include  
#include  
#include  
#include
using namespace std;  
      
//递归方法,求解最长回文子序列  
int lps(char *str, int i, int j)  
{  
    if (i == j)  
        return 1;   //只有一个元素,回文长度为1  
    if (i > j) return 0;   //因为只计算序列str[i....j]  
      
    //如果首尾相同  
    if (str[i] == str[j])  
           return lps(str, i + 1, j - 1) + 2;  
    //如果首尾不同  
    return max(lps(str, i, j - 1), lps(str, i + 1, j));  
}  
int main()  
{  
    char str[] = "cabbeaf";  
    int n = strlen(str);  
    int res = lps(str, 0, n - 1);  
    cout << res<< endl;  
    getchar();  
    return 0;  
} 
#include  
#include 
#include	 
using namespace std;  
 
//动态规划求解最长回文子序列,时间复杂度为O(n^2)  
int lpsDp(char *str, int n)  
{  
    int dp[10][10], tmp;  
    memset(dp, 0, sizeof(dp));  
    for (int i = 0; i < n; ++i)  
		dp[i][i] = 1;  
    for (int i = 1; i < n; ++i)  
    {  
        tmp = 0;  
        //考虑所有连续的长度为i+1的子串,str[j....j+i]  
        for (int j = 0; j + i < n; j++)  
        {  
            //如果首尾相同  
            if (str[j] == str[j + i])  
                tmp = dp[j + 1][j + i - 1] + 2;  
            //如果首尾不同  
            else   
                tmp = max(dp[j + 1][j + i], dp[j][j + i - 1]);  
            dp[j][j + i] = tmp;  
        }  
    }  
    return dp[0][n - 1]; //返回字符串str[0...n-1]的最长回文子序列长度  
}  
      
int main()  
{  
    char str[10] = "cabbeaf";  
    int res = lpsDp(str, strlen(str));  
    cout << res << endl;  
    getchar();  
    return 0;  
}

例:求回文子序列的个数::


#include 
#include 
using namespace std;
int NumOfPalindromeSubSequence(string str){
    int len=str.length();
    vector<vector<int> > dp(len,vector<int>(len));
    for(int j=0;j<len;j++){
        dp[j][j]=1;
        for(int i=j-1;i>=0;i--){
            dp[i][j]=dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1];
            if(str[i]==str[j])
                dp[i][j]+=1+dp[i+1][j-1];
        }
    }
    return dp[0][len-1];
}
int main()
{
    string str;
    int num;
    while(cin>>str){
        num=NumOfPalindromeSubSequence(str);
        cout<<num<<endl;
    }
    return 0;
}

2.最长回文子串
暴力法:

public static String findLongestPalindrome(String s){
        int len = s.length(); // 字符串长度
        int maxlength = 0;  // 最长回文字符串长度
        int start = 0; // 回文开始的地方
        for(int i = 0; i < len; i++){
            for(int j = i + 1; j < len; j++){
                int index1 = 0;
                int index2 = 0;
                // 对每个子串都从两边开始向中间遍历
                for(index1 = i, index2 = j; index1 < index2; index1 ++, index2--){
                    if(s.charAt(index1) != s.charAt(index2))
                        break;
                }
                // 若index1=index2,表示串是类似于abcba这种类型;若大于,则是abccba这种类型
                if(index1 >= index2 && j - i > maxlength){
                    maxlength = j - i + 1;
                    start = i;
                }
            }
 
        }
        if(maxlength > 0)
            return s.substring(start, start + maxlength);
        return null;
 
    }

动态规划:

public static String findLongestPalindrome1(String s){
        int len = s.length();
        int start = 0;
        int maxlength = 0;
        boolean p[][] = new boolean[s.length()][s.length()];
        // 子串长度为1和为2的初始化
        for(int i = 0; i < len; i++){
            p[i][i] = true;
            if(i < len - 1 && s.charAt(i) == s.charAt(i + 1)){
                p[i][i + 1] = true;
                start = i;
                maxlength = 2;
            }
        }
        // 使用上述结果可以dp出子串长度为3~len -1的子串
        for(int strlen = 3; strlen < len; strlen ++){
            for(int i = 0; i <=len - strlen; i++){
                int j = i + strlen - 1; // 子串结束的位置
                if(p[i + 1][j - 1] && s.charAt(i) == s.charAt(j)){
                    p[i][j] = true;
                    maxlength = strlen;
                    start = i;
                }
            }
        }
        if(maxlength > 0)
            return s.substring(start, start + maxlength);
        return null;
    }

中心扩展法:

public static String findLongestPalindrome2(String s){
        int len = s.length();
        int maxlength = 0;
        int start = 0;
        // 类似于aba这种情况,以i为中心向两边扩展
        for(int i = 0; i < len; i++){
            int j = i - 1;
            int k = i + 1;
            while(j >= 0 && k < len && s.charAt(j) == s.charAt(k)){
                if(k - j + 1 > maxlength){
                    maxlength = k - j + 1;
                    start = j;
                }
                j --;
                k ++;
            }
        }
        // 类似于abba这种情况,以i,i+1为中心向两边扩展
        for(int i = 0; i < len; i++){
            int j = i;
            int k = i + 1;
            while(j >= 0 && k <len && s.charAt(j) == s.charAt(k)){
                if(k - j + 1 > maxlength){
                    maxlength = k - j + 1;
                    start = j;
                }
                j --;
                k ++;
            }
        }
        if(maxlength > 0)
            return s.substring(start, start + maxlength);
        return null;
    }

Manacher算法:

public static String findLongestPalindrome3(String s) {
        if(s == null || s.length() < 1)
            return "";
        String str = dealWithS(s);  // 处理一下s,即将给字符串s的中间加上特殊字符,这样无论对于奇数字符还是偶数字符可以做同样的处理
        int[] res = new int[str.length()];
        int R = 0; // 当前所能扩展的半径
        int C = 0; // C位置的半径为R
        int maxC= 0; // 最长的半径的位置
        res[0] = 0;
        for(int i = 1; i < str.length(); i++)
        {
            int j = 2 * C - i;  // i点的对称点
            if(j >= 0 && res[j] < R - i)  // 对称点存在且对称点的回文半径在C的回文中
            {
                res[i] = res[j];
            }
            else  // 否则,需要根据i点一点一点的计算
            {
                int k = 1;
                while(R + k < str.length() && 2 * i - R - k >= 0)
                {
                    if(str.charAt(R + k) == str.charAt(2 * i - R - k))
                        k ++;
                    else
                        break;
                }
                res[i] = R -i + k - 1;
                if(res[i] + i > R)
                {
                    R = res[i] + i;
                    C = i;
                }
            }
            maxC = res[maxC] > res[i] ? maxC : i;  // maxC保存的是回文半径最大的那个点的位置
        }
        String subStr = str.substring(maxC - res[maxC], maxC + res[maxC] + 1);
        StringBuffer sb = new StringBuffer();
        for(int i = 0; i < subStr.length(); i++)
        {
            if(subStr.charAt(i) != '#')
                sb.append(subStr.charAt(i));
        }
        return sb.toString();
    }
    public static String dealWithS(String s)  // 将原字符串进行处理
    {
        StringBuffer sb = new StringBuffer();
        sb.append("#");
        for(int i = 0; i < s.length (); i++)
        {
            sb.append(s.charAt(i));
            sb.append("#");
        }
        return sb.toString();
    }

你可能感兴趣的:(字符串,零碎知识点)