leecode---05---字符串,回文,动态规划---查找最长的回文子串
题意
目的是找到最长的回文子串,必须记录好子串的起点,子串的长度这两个参量,然后将子串返回。
分析
方法1:时间换空间
对于每个点,做两个指针往两边跑,跑的过程中判断是否刷新最长回文的长度。遍历的过程中注意区分一下奇数偶数就可以了,区分奇偶数的方式就是指针要么同时从一个数走,要么同时从当前数和后一个数字走起。
方法二:动态规划
空间换时间的类型
代码
class Solution {
int max;
int start;//因为最后要返回结果所以要记录最长回文子串的开始位置
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) return null;
if (s.length() == 1) return s;
//遍历的时候分成奇数和偶数,奇数对应的位置相同,偶数的话就是两端相同
for (int i = 0; i < s.length(); i++) {
getMaxPalindrome(s,i,i);
getMaxPalindrome(s,i,i+1);
}
//最后返回结果值
return s.substring(start,start+max);
}
//写一个函数,更新从Left往左以及right往右的最大回文
public void getMaxPalindrome(String s,int left,int right) {
//如果左右相等并且没有超出边界的话就继续移动
while (left >=0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
left--;
right++;
}
//循环的结果就是左右两边的参数是不相等的
if (max < right - left + 1 -2) {
start = left + 1;
max = right - left - 1;
}
}
}
空间换时间的方式计算
假设dp[i][j]表示从i到j个字符串是回文字符串。
那么 dp[i][j] = dp[i+1][j-1] && (s.charAt(i) == s.charAt(j))
其中dp[i +1][j-1]涉及到i和j.可能的极限情况就是 i+1==j-1或者两个参数值相邻。那么这就涉及到初始化。
1.dp[i][i]==true
2.dp[i][i+1] == true
第一种动态规划写法是错误的:
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) return null;
if (s.length() ==1) return s;
String result = null;
int max = 1;
int[][] dp = new int[s.length()][s.length()];
//初始化,相邻状态和相等状态
for (int i = 0; i < s.length(); i++) {
dp[i][i] = 1;
result = String.valueOf(s.charAt(i));
}
for (int i = 0; i < s.length() - 1; i++) {
if (s.charAt(i) == s.charAt(i + 1)) {dp[i][i + 1] = 1;max = 2;result = s.substring(i,i+2);}
}
//这边的写法是错误的!!!假设从i=0开始,j从2开始往右边跑直到4。但是一开始bcb的dp值是0,因为是从左往右遍历的,所以在判断abcba的时候虽然头尾都是相等的,但是bcb的dp值是0,也就是说abcba也是0,所以不能够从左往右遍历!!!!
//然后进行动态规划判断普通情况dp[i][j]从i到j的值
//1.第一层循环的终点是左边在length - 2的位置
//2.第二层循环的点j从i+2开始,因为相邻和相等情况之前判断过了
//3.判断i和j指向的值是否是相等的,如果相等更新下最大值
for (int i = 0; i < s.length() -2; i++) {
for (int j = i + 2; j < s.length(); j++) {
if (s.charAt(i) == s.charAt(j)) {
dp[i][j] = dp[i + 1][j - 1];
if (dp[i][j] == 1 && (j - i + 1) > max) {
max = j - i + 1;
result = s.substring(i,j+1);
}
} else {
dp[i][j] = 0;
}
}
}
//返回结果
return result;
}
}
动态规划的正确解法,应该按照长度大小来设置普通情况下的字符串长度。
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) return null;
if (s.length() ==1) return s;
String result = null;
int max = 1;
int[][] dp = new int[s.length()][s.length()];
//初始化,相邻状态和相等状态
for (int i = 0; i < s.length(); i++) {
dp[i][i] = 1;
result = String.valueOf(s.charAt(i));
}
for (int i = 0; i < s.length() - 1; i++) {
if (s.charAt(i) == s.charAt(i + 1)) {dp[i][i + 1] = 1;max = 2;result = s.substring(i,i+2);}
}
//然后进行动态规划判断普通情况dp[i][j]从i到j的值
//必须从长度开始判断,长度从3开始处理
for (int l = 3; l <= s.length(); l++) {
for (int i = 0; i + l - 1 < s.length(); i++) {
int j = i + l - 1;//就是加上长度之后的右边的值
if (s.charAt(i) == s.charAt(j)) {
dp[i][j] = dp[i + 1][j - 1];
if (dp[i][j] == 1 && l > max) {
max = l;
result = s.substring(i,j + 1);
}
} else {
dp[i][j] = 0;
}
}
}
//返回结果
return result;
}
}