- 回文字符就是指的是正着读,反着读,都一样的字符串。比如‘abcbaqes’中的‘abcba’就是一个回文字符 长度为5
这题其实和查找数字中最大回文数长度的做法是一样的道理
一、两边收缩法
找到字符串的所有子串,遍历每一个子串以验证它们是否为回文串。一个子串由子串的起点和终点确定,因此对于一个长度为n的字符串,共有n^2个子串。这些子串的平均长度大约是n/2,因此这个解法的时间复杂度是O(n^3)。
显然这种方法十分暴力。那么有没有更不耗时间的方法呢?
二、中心拓展法
由于我们的字符串是回文字符串,那么当我们选择到回文数中间的数时,判断左右两边的字符是否相等。如果相等的话继续判断更旁边的字符是否相等。如果不相等,记录下此时回文数的长度,和最大值比较。
以上面的方法,遍历每个字符为中心,最后输出结果即为最大回文数。
//核心算法
private static int p(String a) {
int max = 0;
for (int i = 0; i < a.length()-1; i++) {
for (int j = 0; i-j>=0&&j+i<a.length(); j++) { //当回文数为奇数时
//i-j代表靠近左边距离为j的字符,i+j同理。
if(a.charAt(i-j)!=a.charAt(i+j))
{
break;
}else {
max = max>(2*j+1)?max:(2*j+1); //2*j+1为当前奇数回文数的长度
}
//继续寻找旁边的相等字符
}
for (int j = 0; i-j>=0&&j+i+1<a.length(); j++) { //当回文数为偶数时
//i-j代表靠近左边距离为j的字符,i+j同理。
if(a.charAt(i-j)!=a.charAt(i+j+1))
{
break;
}else {
max = max>(2*j+2)?max:(2*j+2); //2*j+1为当前奇数回文数的长度
}
//继续寻找旁边的相等字符
}
}
return max; //返回最大回文数的长度
}
这个算法稍微优化了一下我们上面的暴力求解,复杂度变成O( n2 n 2 )
动态规划
动态规划和上面马拉松的时间复杂度是一样的 没学过动态规划的同学可以看这里动态规划初步
3/28号更新
当我们字符串变得足够大的时候显然我们这样的算法是不行的。We can do it better
Manacher算法(马拉车算法)
主要算法思路在Manacher算法详解里可以看到,这里我们就直接讲思路
我们上面的几个算法中我们需要算出分两种情况,一种奇数,一种偶数。这样就要进行两次循环,浪费了时间。
马拉车算法,主要就是在每个字符中插入‘#’使他的回文数全部变成奇数,这样只用求解一种情况。例如:
aba->#a#b#a#
核心算法:
private static int Manacher(String a) {
int pos = 0;
String T = init(a);
char[] t = T.toCharArray();
int mx = 0;
for (int i = 1; i < t.length; i++) {
if (mx > i) {
p[i] = Math.min(p[2 * pos - i], mx - i);
} else {
p[i] = 1;
}
while (i+p[i]<t.length&&i-p[i]>0&&t[i-p[i]]==t[i+p[i]]) {
p[i]++;
}
if(mx<p[i]+i)
{
pos = i;
mx = p[i]+i;
}
max = Math.max(max,p[i]-1);
}
return max;
}
这样的话我们的复杂度就由 n(o2) n ( o 2 ) 变成了线性的 n(o) n ( o )