【LeetCode】5. 最长回文子串

5. 最长回文子串

知识点:动态规划;回文串

题目描述

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

示例
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

输入:s = "cbbd"
输出:"bb"

输入:s = "a"
输出:"a"

输入:s = "ac"
输出:"a"

解法一:暴力法

从头开始找最长回文子串;记录最长串的开始位置和长度,最后从s中截取就可以了;

class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        if(len < 2) return s;
        int maxLen = 1;
        int begin = 0;  //得到起始位置和长度就能得到了;
        char[] ch = s.toCharArray();
        for(int i = 0; i < len-1; i++){
            for(int j = i+1; j < len; j++){
                //最长回文子串:是回文串,而且大于之前的长度;
                if(j-i+1 > maxLen && isHuiWen(ch, i, j)){
                    maxLen = j-i+1; 
                    begin = i;
                }
            }
        }
        return s.substring(begin, begin+maxLen);
    }
    private boolean isHuiWen(char[] ch, int start, int end){
        while(start < end){
            if(ch[start] == ch[end]){
                start++;
                end--;
            }else{
                return false;
            }
        }
        return true;
    }
}

解法二:动态规划;

此题可以用动态规划去做,因为回文串天然具有状态转移的性质,比如一个子串如果是回文子串,那把前后两个字符去掉后依然是回文子串。那反过来,就可以根据前面的子串来判断新的子串了。

  • 1.确定dp数组和其下标的含义;dp[i][j]表示子串s[i:j]是否是回文子串;
  • 2.确定递推公式,即状态转移方程;先填写j,因为i必须在j前面,i<j;判断首尾字符,如果不相等直接false,如果相等,那就状态转移,dp[i][j] = dp[i+1][j-1];
  • 3.dp初始化;base case; 长度为1的,也就是dp[i][i]=true;
class Solution {
    public String longestPalindrome(String s) {
        int maxLen = 1;
        int begin = 0;
        int len = s.length();
        boolean[][] dp = new boolean[len][len]; //s[i:j]是否是回文串;
        for(int i = 0; i < len; i++){
            dp[i][i] = true;  //长度为1肯定都是;
        }
        char[] ch = s.toCharArray();
        for(int j = 1; j < len; j++){
            for(int i = 0; i < j; i++){
                //头尾不等,肯定不是;
                if(ch[i] != ch[j]){
                    dp[i][j] = false;
                }else{
                    //两者中间没有元素或者有一个元素,true;
                    if(j-i <= 2){
                        dp[i][j] = true;
                    }else{
                        dp[i][j] = dp[i+1][j-1]; //状态转移;
                    }
                }
                if(dp[i][j] && j-i+1 > maxLen){
                    maxLen = j-i+1;
                    begin = i;
                }
            }
        }
        return s.substring(begin,begin+maxLen);
    } 
}
  • python
class Solution:

    def findLongestHuiWenStr(self, s: str) -> str:
        if len(s) < 2:
            return s
        begin = 0
        maxlen = 1
        dp = [[False] * len(s) for _ in range(len(s))]

        for i in range(len(s)):
            dp[i][i] = True
        for j in range(1, len(s)):
            for i in range(j):
                if s[i] != s[j]:
                    dp[i][j] = False
                else:
                    if j-i <= 2:
                        dp[i][j] = True
                    else:
                        dp[i][j] = dp[i+1][j-1]
                if dp[i][j] and j-i+1 > maxlen:
                    maxlen = j-i+1
                    begin = i
        return s[begin:begin+maxlen]

解法三:中心扩散;

从头到尾去进行遍历,然后以该元素为中心值去扩散,比较扩散的两端的值是否相等,相等的话就接着扩散,不等的话就返回最大子串的长度。

注意细节就是奇数和偶数是不同的,比如aba以b扩散,和abba以bb进行扩散,所以扩散的时候左右两点分别是[i,i]和[i,i+1];

class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        int maxLen = 1;
        int begin = 0;
        for(int i = 0; i < len-1; i++){
            int len1 = expandCenter(s, i, i); //偶数中心扩散;
            int len2 = expandCenter(s, i, i+1); //奇数中心扩散;
            len1 = Math.max(len1, len2);
            if(len1 > maxLen){
                maxLen = len1;
                begin = i-(maxLen-1)/2; //奇数:i-maxLen/2; 偶数:i-maxLen/2+1; 将两者统一;
            }
        }
        return s.substring(begin, begin+maxLen);
    }
    private int expandCenter(String s, int left, int right){
        while(left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){
            left--;
            right++;
        }
        return right-left-1;  //最后两个是已经越界的。right-left+1-2;
    }
}
    def findLongestHuiWenStr(self, s: str) -> str:
        if len(s) < 2:
            return s
        begin = 0
        maxlen = 0
        len = 1
        for i in range(len(s)):
            left = i-1
            right = i+1
            while left >= 0 and s[left] == s[i]:
                len += 1
                left -= 1
            while right < len(s) and s[right] == s[i]:
                len += 1
                right += 1
            while left >= 0 and right < len(s) and s[right] == s[left]:
                len += 2
                left -= 1
                right += 1
            maxlen = max(maxlen, len)
            begin = left
            len = 1
        return s[begin+1:begin+1+maxlen]
posted @ 2021-08-14 02:43  Curryxin  阅读(103)  评论(0编辑  收藏  举报
Live2D