Leetcode5. 最长回文子串

因为队友原因,自己退出了ICPC小组,Codeforces可能不打下去了,从今天开始更新Leetcode题目(1天5题左右)。(5天连一道题目都不补的纯➗生)

首先我点开非常重要的动态规划,DP一共454题,准备一天5题按顺序做完。

使用的语言均为Java。

5.最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。

题意非常明显,让我们找到最长回文子串。我们有多种思路来解决这个问题。

1.DP:设dp[i][j]为从s[i]到s[j](其中s[i]………s[j]为回文子串需要判断,所以将dp这个二维数组设置为boolean类型) 首先我们需要特判:s.length()<2时,return s即可;其余情况,我们就需要一个maxLen变量,来更新答案。首先声明一个数组,并声明一个char数组来遍历字符串s:

        int len=s.length();
        if(len<2)   return s;
        int maxLen=1;
        int begin=0;
        // dp[i][j]表示s[i..j] 是否是回文串
        boolean [][] dp=new boolean[len][len];
        for(int i=0;i<len;i++){
            dp[i][i]=true;
        }
        char []charArray=s.toCharArray();

然后,枚举左边界求出右边界,j-i+1=L,枚举L和i,那么j=L+i-1;转移状态方程也很好想:dp[i][j]=true(s[i]………s[j]为回文子串)  dp[i][j]=false(其中s[i]………s[j]不为回文子串)

但是在false处有两种情况,一种是i>j明显不符合左右边界的特点(左边界一定在右边界左边);还有一种是s[i]………s[j]不为回文子串。

可以写出状态转移方程:

 for(int L=1;L<=len;L++){
            for(int i=0;i<len;i++){
                int j=L+i-1;
                if(j>=len)  break;
                if(charArray[i]!=charArray[j]){
                    dp[i][j]=false;
                }
                else{
                    if(j-i<3)   dp[i][j]=true;
                    else    dp[i][j]=dp[i+1][j-1];
                }

然后处理完就需要更新maxLen了,当dp[i][j]==true&&j-i+1>maxLen时,我们就更新maxLen即可。

                if(dp[i][j]&&j-i+1>maxLen){
                    maxLen=j-i+1;
                    begin=i;
                }

最后调库输出substring即可。

最终代码:

class Solution {
    public String longestPalindrome(String s) {
        int maxLen=1;
        int len=s.length();
        int begin=0;
        if(len<2)   return s;
        boolean [][]dp=new boolean[len][len];
        for(int i=0;i<len;i++){
            dp[i][i]=true;
        }
        char []charArray=s.toCharArray();
        for(int L=1;L<=len;L++){
            for(int i=0;i<len;i++){
                int j=L+i-1;
                if(j>=len)  break;
                if(charArray[i]!=charArray[j]){
                    dp[i][j]=false;
                }        
                else{
                    if(j-i<3)   dp[i][j]=true;
                    else{
                    dp[i][j]=dp[i+1][j-1];//two pointers
                    }
                }           
                if(dp[i][j]&&j-i+1>maxLen){
                    maxLen=j-i+1;
                    begin=i;
                }
            }
        }
        return s.substring(begin,begin+maxLen);
    }
}

2.中心扩散法:

从中间向两边扩散开,实际上运用的是双指针思想,写一个expand函数,当left左指针>=0&&right右指针<s.length()&&s.charAt(left)==s.charAt(right)时,左指针left++,右指针right--;然后设置两个变量start和end,通过遍历求出max(expand(s,i,i),expand(s,i,i+1)),更新start和end,最后输出子串即可。

class Solution {
    public String longestPalindrome(String s) {
        if(s==null||s.length()<1) return "";
        int start=0;
        int end=0;
        int len=s.length();
        for(int i=0;i<len;i++){
            int len1=expand(s,i,i);
            int len2=expand(s,i,i+1);
            int lenMax=Math.max(len1,len2);
            if(lenMax>end-start){
                start=i-(lenMax-1)/2;
                end=i+lenMax/2;
            }
        }
        return s.substring(start,end+1);
    }
    public int expand(String s,int left,int right) {
        while(left>=0&&right<s.length()&&s.charAt(left)==s.charAt(right)) {
            --left;
            ++right;
        }
        return right-left-1;
    }
}

 

posted @ 2022-07-27 10:49  cf不上1500不改名  阅读(12)  评论(0)    收藏  举报