最长回文子串(longest-palindromic-substring)

题目

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

代码

解法 1: 暴力破解

暴力求解,列举所有的子串,判断是否为回文串,保存最长的回文串。


// 暴力解法
public String longestPalindrome(String s) {
    String ans = "";
    int max = 0;
    int len = s.length();
    for (int i = 0; i < len; i++)
        for (int j = i + 1; j <= len; j++) {
            String test = s.substring(i, j);
            if (isPalindromic(test) && test.length() > max) {
                ans = s.substring(i, j);
                max = Math.max(max, ans.length());
            }
        }
    return ans;
}

public boolean isPalindromic(String s) {
		int len = s.length();
		for (int i = 0; i < len / 2; i++) {
			if (s.charAt(i) != s.charAt(len - i - 1)) {
				return false;
			}
		}
		return true;
}

解法2 : 动态规划

方法一中,存在大量的重复计算工作,例如当 s=“abcba” 时, 对于子串 “bcb” 和 子串 “abcba”, 分别进行了2次完整的计算,来检测该子串是否是回文串。

很明显的是,对于 s=“abcba” , 在已知 "bcb"是回文串的情况下,要判断 "bcb"是否是回文串的话,只需要判断两边的*位置的字符是否相等即可。 我们定义 P(i,j) 表示 s[i,j]是否是回文串,若s[i,j]是回文串,则P(i,j)=true,否则为false. 则有下面的递推公式成立:

P[i,j] =  p(i+1,j-1) && ( s[i]==s[j] ) 

对于上面公式有2个特殊情况,当子串长度为1或2时,上面公式不成立。我们单独分析这两种情况:

若子串长度为1,即 j==i, 则 P[i,j] = P[i,i] = true; 
若子串长为2,即j==i+1, 则 P[i,j] = P[i,i+1] =  ( s[i]==s[i+1] )

在实际执行时,我们先求所有长度为1的子串的P值,再求所有长度为2的子串的P值,之后再求长度3的,以此类推,一直到长度为s.Length的。例如 s=“abcba” ,则P的值 类似下图:
在这里插入图片描述
代码

    public String longestPalindrome(String s) {
		if (s == null || s.length() < 2) {
			return s;
		}
		int strLen = s.length();
		int start = 0; // 最长回文串的起点
		int end = 0; // 最长回文串的终点
		int maxLen = 1; // 最长回文串的长度

		boolean[][] dp = new boolean[strLen][strLen];

		for (int r = 1; r < strLen; r++) {//思考,为什么要从1开始
			for (int l = 0; l < r; l++) {
				if ((r - l <= 2 || dp[l + 1][r - 1]) && s.charAt(l) == s.charAt(r)) {
					dp[l][r] = true;
					if (r - l + 1 > maxLen) {//思考,为什么要加 1
						maxLen = r - l + 1;
						start = l;
						end = r;
					}
				}
			}
		}
		return s.substring(start, end + 1);//思考,为什么要加 1
    }

思考,为什么要从1开始?因为是中心扩散法,两边没有值怎么扩散。
思考,为什么要加1?因为数组[1,2,3]的下标为0,1,2。但是长度为3。
思考,为什么要加 1?因为substring方法返回的是beginIndex到endIndex-1的字符。
注意
DP数组初始化时,当right-1== left+1 的时候就是两边界相等的时候,移项,得right-left==2,所有有r-l<=2的时候就是区间不存在的情况,这个时候dp[l][r]是没有意义的。

若子串长度为1,dp[i,i] = true
若子串长为2,则 dp[i,j] = dp[i,i+1] = ( s[i]==s[i+1] )
子串长度为1,都是True,子串长度为2时,要判断。

资料

windliang资料
LeetCode 5. Longest Palindromic Substring 最长回文子串 C#

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章