动态规划---最长子串/子序列问题序列1
5. 最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
解法1:动态规划
- 1、当子串只包含 1 个字符,它一定是回文子串;
- 2、当子串包含 2 个以上字符的时候:如果 s[l, r] 是一个回文串,例如 “abccba”,那么这个回文串两边各往里面收缩一个字符(如果可以的话)的子串 s[l + 1, r - 1] 也一定是回文串,即:如果 dp[l][r] == true 成立,一定有 dp[l + 1][r - 1] = true 成立。
根据这一点,我们可以知道,给出一个子串 s[l, r] ,如果 s[l] != s[r],那么这个子串就一定不是回文串。如果 s[l] == s[r] 成立,就接着判断 s[l + 1] 与 s[r - 1],这很像中心扩散法的逆方法。 - 时间和空间都是o(n^2).
- 强调:
状态定义: dp[i][j] 表示数组子串 s[i, j] 是否为回文子串。
状态转移方程: dp[l, r] = (s[l] == s[r] and (r - l <= 2 or dp[l + 1, r - 1]))
class Solution {
public String longestPalindrome(String s) {
if (s.length() <= 1) {
return s;
}
int len = s.length();
int longestStrLength = 1;
String longestStr = s.substring(0,1);
//dp[left][right] 表示从left到right是否是回文子串
boolean[][] dp = new boolean[len][len];
for (int right=0; right<len; right++) {
for (int left=0; left<right; left++) {
//1 如果 dp[l, r] = true 那么 dp[l + 1, r - 1] 也一定为 true,所以反过来递推
//2 剪枝:如果left到right间的数只有一个或者没有,比如left=1> right=2(中间没有数)或者1>3(中间只有一个数),则不用判断,中间的数肯定是回文的
//3 left到right间的数:至少有2个才有判断:dp[left+1][right-1]的必要。
if (s.charAt(left) == s.charAt(right) && (right-left <=2 || dp[left+1][right-1])) {