LeetCode Top 100 Liked Questions 5.Longest Palindromic Substring (Java版; Medium)

welcome to my blog

LeetCode Top 100 Liked Questions 5.Longest Palindromic Substring (Java版; Medium)

题目描述

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"
class Solution {
    public String longestPalindrome(String s) {
        int n = s.length();
        if(n==0){
            return "";
        }
        //dp[i][j]表示s[i,j]是否是回文子串
        //dp[i][j] = dp[i+1][j-1] && s[i]==s[j] else
        //dp[i][j] = s[i]==s[j]   if i+1==j
        boolean[][] dp = new boolean[n][n];
        //初始化有讲究
        int[] tmp = {0,1};
        for(int i=0; i<n; i++){
            dp[i][i] = true;
        }
        for(int i=n-1; i>=0; i--){
            for(int j=i+1; j<n; j++){
                if(i+1==j){
                    dp[i][j] = s.charAt(i)==s.charAt(j);
                }else{
                    dp[i][j] = dp[i+1][j-1] && s.charAt(i)==s.charAt(j);
                }
                if(dp[i][j] && j-i+1 > tmp[1]){
                    tmp[1] = j - i + 1;
                    tmp[0] = i;
                }
            }
        }
        return s.substring(tmp[0], tmp[0]+tmp[1]);
    }
}
第二次做; 动态规划 核心: 1)dp[i][j]表示s[i,j]是否是回文子串 2)i相当于左边界, j相当于右边界, 左边界不能超过右边界 3)递推公式见注释 4)根据依赖关系可知, 需要从下往上, 从左往右遍历 5)先保存区间, 最后再用substring, 节省空间
class Solution {
    public String longestPalindrome(String s) {
        //input check
        if(s==null || s.length()<=1){
            return s;
        }
        /*
        dp[i][j]表示s[i,j]是不是回文子串; 
        i相当于左边界, j相当于右边界, i<=j

        dp[i][j] =  s[i]==s[j] && (j-i<=2 || dp[i+1][j-1])
        */
        int n = s.length();

        boolean[][] dp = new boolean[n][n];

        //res[0]表示左边界, res[1]表示右边界, res[2]表示最大长度
        int[] res = {0,0,0};
        for(int i=n-1; i>=0; i--){
            for(int j=i+1; j<n; j++){
                dp[i][j] = s.charAt(i)==s.charAt(j) && (j-i<=2 || dp[i+1][j-1]);
                if(dp[i][j] && j-i+1>res[2]){
                    res[2] = j-i+1;
                    res[0] = i;
                    res[1] = j;
                }
            }
        }
        return s.substring(res[0], res[1]+1);
    }
}
第二次做; 中心扩展法
class Solution {
    public String longestPalindrome(String s) {
        //input check
        if (s == null || s.length() <= 1) {
            return s;
        }
        //记录回文串的左右边界
        int left = 0, right = 0;
        int n = s.length();
        for (int i = 0; i < n; i++) {
            int len1 = expand(s, i, i);
            int len2 = expand(s, i, i + 1);
            if (len1 > len2 && len1 > right - left + 1) {
                left = i - len1 / 2;
                right = i + len1 / 2;
            } else if (len2 > len1 && len2 > right - left + 1) {
                left = i - (len2 - 2) / 2;
                right = i+1 + (len2 - 2) / 2;
            }
        }
        return s.substring(left, right + 1);
    }

    private int expand(String s, int x, int y) {
        int left = x, right = y;
        while (x >= 0 && y < s.length() && s.charAt(x) == s.charAt(y)) {
            x--;
            y++;
        }
        return y - x - 1;
    }
}
第一次做, 统一长度的更新公式; 调整了for循环条件, while循环条件
class Solution {
    public String longestPalindrome(String s) {
        if(s==null || s.length()<2)
            return s;
        int left = 0, right = 0;
        int len1 = 0, len2 = 0;
        //比起上一次修改了i的终止条件
        for(int i=0; i<s.length(); i++){
            len1 = centerExpand(s, i, i);
            len2 = centerExpand(s, i, i+1);
            
            len1 = Math.max(len1, len2);
            if(len1 > right - left + 1){
                left = i - (len1 - 1)/2;
                right = i + len1/2;              
            }
        }
        return s.substring(left, right+1);
    }
    public int centerExpand(String s, int i, int j){
        int left=i, right=j;
        while(left>=0 && right<s.length() && s.charAt(left)==s.charAt(right)){
            left--;
            right++;
        }
        return right - left - 1;
    }
}
第一次做, 使用中心扩展法
  • 中心可能是同一个字符, 也可能是相邻的两个字符;
  • 字符串长度小于2时直接返回;
  • 注意循环终止条件, s至少有两个字符才会进入循环
  • 长度一次增加2
class Solution {
public String longestPalindrome(String s) {
        //字符串长度小于2时直接返回
        if(s==null || s.length()<2)
            return s;
        String curr = "";
        int len1, len2;
        int left, right;
        //注意循环终止条件, s至少有两个字符才会进入循环
        for(int i=0; i<s.length()-1; i++){
            len1 = centerExpand(s, i, i);
            len2 = centerExpand(s, i, i+1);
            if(len1 > len2){
                left = i - (len1 - 1)/2;
                right = i + (len1 -1)/2; //可以写成i + len1/2
                curr = len1 > curr.length() ? s.substring(left, right+1) : curr;
            }
            else{
                left = i - (len2-2)/2; //可以写成i-(len2-1)/2 和一个中心点的情况统一了
                right = i + 1 + (len2-2)/2; //可以写成i + len2/2
                curr = len2 > curr.length() ? s.substring(left, right+1) : curr;
            }
        }
        return curr;
    }
    public int centerExpand(String s, int i, int j){
        // 相邻两个字符不同, 直接返回0
        if(s.charAt(i) != s.charAt(j))
            return 0;
        int len = j - i + 1;
        int step=1;
        while((i-step)>=0 && (j+step)<s.length()){
            if(s.charAt(i-step) == s.charAt(j+step)){
                //长度一次加2!
                len += 2;
                step++;
            }
            else
                break;
        }
        return len;
    }
}
题解中心扩展法
public String longestPalindrome(String s) {
    if (s == null || s.length() < 1) return "";
    int start = 0, end = 0;
    for (int i = 0; i < s.length(); i++) {
        int len1 = expandAroundCenter(s, i, i);
        int len2 = expandAroundCenter(s, i, i + 1);
        int len = Math.max(len1, len2);
        if (len > end - start) {
            start = i - (len - 1) / 2;
            end = i + len / 2;
        }
    }
    return s.substring(start, end + 1);
}

private int expandAroundCenter(String s, int left, int right) {
    int L = left, R = right;
    while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {
        L--;
        R++;
    }
    return R - L - 1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值