Longest Palindromic Substring(最长回文子串)

本文探讨了三种高效算法:暴力法、中心扩展法及动态规划法,用于在字符串中找到最长的回文子串。通过实例展示了每种方法的实现细节与优劣对比。

Description:

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example 1:

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Example 2:

Input: "cbbd"
Output: "bb"

1,暴力法

  判断字符串s的所有子串a是否为回文字符串,如果是,则返回字符串a与其长度l。最终返回长度最长的回文子串。

class Solution {
    public String longestPalindrome(String s) {
        String s1;
        String st = null;
        int maxLenrth = 0;
        if (s.length() == 1 || s.length() == 0) {
            return s;
        }else {
            for (int i = 0; i < s.length(); i++) {
                for (int j = i; j < s.length(); j++) {
                    s1 = s.substring(i, j+1);
                    if (isHw(s1)>maxLenrth) {
                        maxLenrth = isHw(s1);
                        st = s1;
                    }
                }
            }
            return st;
        }
    }
    
  //判断是否为回文 是返回其长度 否返回0
public int isHw(String s){ for (int i = 0; i < s.length()/2; i++) { if (s.charAt(i) != s.charAt(s.length()-i-1)) { return 0; } } return s.length(); } }

 2,中心扩展法

中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展,这样来找最长的子回文串。算法复杂度为O(N^2)。
需要考虑两种情况:
长度为奇数的回文串,比如a, aba, abcba
长度为偶数的回文串,比如aa, abba

    //最长回文子串 -- 中心扩展法
    public static String longestHWStrings(String s){
        
        int len = s.length();
        int maxlen = 1;
        int start = 0;
        
        //长度为奇数的回文串
        for (int i = 0; i < len; i++) {
            int j = i-1,k = i+1;
            while(j>=0 && k<len && s.charAt(j)==s.charAt(k)){
                if(k-j+1 > maxlen){
                    maxlen = k-j+1;
                    start = j;
                }
                j--;
                k++;
            }
        }
        
        //长度为偶数的回文串
        for (int i = 0; i < len; i++) {
            
            int j = i,k = i+1;
            while(j>=0 && k<len && s.charAt(j)==s.charAt(k)){
                if(k-j+1 > maxlen){
                    maxlen = k-j+1;
                    start = j;
                }
                j--;
                k++;
            }
        }
        
        return s.substring(start,start+maxlen);
    }

 

3,动态规划

使用动态规划的策略解决该问题。首先,从子问题出发,并将子问题的解保存起来,然后在求解后面问题时,反复利用子问题的解,可以极大的提高效率。

由于最长回文子串是要求连续的,所以我们可以假设 j 为子串的起始坐标,i 为子串的终点坐标,其中 i 和 j 都是大于等于 0 并且小于字符串长度 len 的,且 j <= i,这样子串的长度就可以使用 i - j + 1 表示了。

我们从长度为 1 的子串依次遍历,长度为 1 的子串肯定是回文的,其长度就是 1;然后是长度为 2 的子串依次遍历,只要 str[i] 等于 str[j] ,它就是回文的,其长度为 2;接下来就好办了,长度大于 2 的子串,如果它要满足是回文子串的性质,就必须有 str[i] 等于 str[j] ,并且去掉两头的子串 str[j+1 ... i-1] 也一定是回文子串,所以我们使用一个数组来保存以 j 为子串起始坐标,i为子串终点坐标的子串是否是回文的,由于我们是从子问题依次增大求解的,所以求解 [i ... j] 的问题时,比它规模更小的问题结果都是可以直接使用的了。  引用

状态方程和转移方程:

  1.       P[i, j] = P[i+1, j-1], if ( s[i]==s[j] )
  2.       P[i, j] = false,if ( s[i] != s[j] )
    //LPS -- 最长回文子串  动态规划
    public static String getLPS(String s){
        
        if(s.equals("")){
            return "";
        }
        
        char[] c = s.toCharArray();
        int len = c.length;
        //第一维参数表示起始坐标  第二维参数表示终点坐标
        //lps[j][i]表示以j为起始坐标i为终点坐标的字符串是否为回文字符串 
        boolean lps[][] = new boolean[len][len];
        int maxlen = 1;
        int start = 0;
        for (int i = 0; i < len; i++) {
            for (int j = 0; j <= i; j++) {
                if(i-j<2){
                    lps[j][i] = c[j]==c[i];
                }else{
                    lps[j][i] = lps[j+1][i-1] && (c[j]==c[i]);
                }
                
                if(lps[j][i] && (i-j+1)>maxlen){
                    maxlen = i-j+1;
                    start = j;
                }
            }
        }
        return s.substring(start,start+maxlen);
    }

 

转载于:https://www.cnblogs.com/wkcode/p/10360433.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值