暴力解法:
列举所有的子串,判断是否为回文串,保存最长的回文串。
/*
* 暴力解法: 列举所有的子串,判断是否为回文串,保存最长的回文串。
*/
public int getLongestPalindrome(String A, int n) {
if(n == 0 || n == 1)
return n;
int count = 0;
String temp;
for (int i = 0; i < n; i++) {
for (int j = i+1; j <= n; j++) {
// 截取字符串
temp = A.substring(i,j);
// 判断字符串是否为回文
if(isPalindrome(temp) && (j-i) > count){
count = j-i;
}
}
}
return count;
}
private boolean isPalindrome(String str){
int start=0;
int end=str.length()-1;
while(start<end){
if(str.charAt(start) == str.charAt(end)){
start++;
end--;
}else{
return false;
}
}
return true;
}
动态规划(利用已有的信息,判断下一步)
暴力解法时间复杂度太高,我们可以考虑,去掉一些暴力解法中重复的判断。
首先定义:字符串 s 从下标 i 到下标 j 的字串为 P(i, j),若 s 从下标 i 到下标 j 的字串为回文串,则 P(i, j) = true,否则 P(i, j) = false。如下图所示:
则 P(i, j) = (P(i + 1, j - 1) && s[i] == s[j])。
所以如果我们想知道 P(i,j)的情况,不需要调用判断回文串的函数了,只需要知道 P(i+1,j−1)的情况就可以了,这样时间复杂度就少了 O(n)。因此我们可以用动态规划的方法,空间换时间,把已经求出的 P(i,j)存储起来。
如果 s[i+1, j-1] 是回文串,那么只要 s[i] == s[j],就可以确定 s[i, j] 也是回文串了。
注意:
求 长度为 1 和长度为 2 的 P(i, j) 时不能用上边的公式,因为我们代入公式后会遇到 P[i][j] 中 i > j 的情况,比如求P[1][2] 的话,我们需要知道 P[1+1][2-1]=P[2][1] ,而 P[2][1] 代表着 S[2, 1] 是不是回文串,这显然是不对的,所以我们需要单独判断。
所以我们先初始化长度是 1 的回文串的 P [i , j],这样利用上边提出的公式 P(i,j)=(P(i+1,j-1) && S[i]==S[j]),然后两边向外各扩充一个字符,长度为 3 的,为 5 的,所有奇数长度的就都求出来了。同理,初始化长度是 2 的回文串 P[i,i+1],利用公式,长度为 4 的,6 的所有偶数长度的就都求出来了。
public int getLongestPalindrome(String A, int n) {
int sLen = n;
int maxLen = 0;
String ans = "";
boolean[][] P = new boolean[sLen][sLen];
// 遍历所有长度 "abc1234321"
for (int len = 1; len <= sLen; len++) {
for (int start = 0; start < sLen; start++) {
int end = start + len - 1;
// 下标越界,结束循环
if (end >=sLen) {
break;
}
P[start][end] = (len == 1 || len == 2 || P[start + 1][end - 1]) && A.charAt(start) == A.charAt(end);
if (P[start][end] && len > maxLen) {
maxLen = len;
ans = A.substring(start, end + 1);
}
}
}
return ans.length();
}