关于最长回文子串的问题

pandm 2011-03-10 02:12:24
输入一个字符串str,要求输出str里的最长回文子串。



===========================================
分类枚举,偶数长度的回文和奇数长度的回文。
如果是奇数长度的回文,枚举中心字符的位置,向两边逐步扩展,一旦失败马上枚举下一个。
偶数的类似。

想不到其他特别好的方法了。
大家有别的好方法吗?
...全文
575 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
studentneo 2012-09-11
  • 打赏
  • 举报
回复
http://acm.uestc.edu.cn/bbs/read.php?tid=3258
xsj_guagua 2011-03-10
  • 打赏
  • 举报
回复
可以用后缀数组实现,将目标串r分解为后缀数组p[k],再将r逆转,分解为后缀数组q[k],数组下标代表后缀数在原字符串内开始的位置
将p[k],q[k]按首字母大小排序,然后依次从上至下进行比较,只比较有相同前缀开头的两个串,如果遇到公共串的,比较它们的数组下标所在的区间是不是一样(q[k]的逆转一下)。
这样扫描一遍,即可取得最大值。
粗略估计,按字母排序的复杂度O(n*logn),扫描的复杂度在O(n)

这里好像排序我想不到什么好方法,似乎通过建立类似tire的后缀树可以避免排序,这个还是等大牛来解答下
keeya0416 2011-03-10
  • 打赏
  • 举报
回复
哎 这自己写的代码我现在自己都看不懂了
杯具
这个算法的主要核心思想就是一个回文如果前缀有回文那么其后缀必有与其对应的另一个回文
通过这个规律不断找到当前轴的下一个轴
上边这个代码还有一个Bug
通过插入一个'0'将任意一个字符串转换成有奇数个字节
当原字符串中有'0'字符时,有时候会出错
keeya0416 2011-03-10
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 litaoye 的回复:]
我以前也犯过同样的错误。

n^2的方法就是枚举每个字符,依次统计回文的长度。
有个近似O(n)的方法,不过真的很复杂,有些类似于dp,到现在我对该方法还是迷迷糊糊的。


引用 1 楼 knightzhuwei 的回复:
输入str
取str的逆序列str2
这时就转化为求str与str2的最长公共子序列的问题 这个有现成算法的吧
[/Quote]
我就献丑把那个近似O(n)的方法贴上来吧
其实也是litaoye大牛给我介绍的

public static String getPalindrome(String str) {
char[] strArr = str.toCharArray();
char[] newStrArr = new char[2 * str.length() + 1];
for (int i = 0; i < newStrArr.length; i++) {
if (i % 2 == 0) {
newStrArr[i] = '0';
} else {
newStrArr[i] = strArr[i / 2];
}
}
int[] radiiArr = new int[newStrArr.length];
int maxRadii = 1;
int center = 1;
int radii = 1;
loop: while (center < radiiArr.length) {
while (center + (++radii) < newStrArr.length && center - radii >= 0
&& newStrArr[center + radii] == newStrArr[center - radii])
;
radiiArr[center] = --radii;
maxRadii = radiiArr[center] > radiiArr[maxRadii] ? center
: maxRadii;
if (radiiArr[center] == 0) {
center++;
radii = 0;
} else {
for (int index = center - 1; index >= center - radiiArr[center]; index--) {
if (center - radiiArr[center] < index - radiiArr[index]) {
radiiArr[2 * center - index] = radiiArr[index];
} else if (center - radiiArr[center] > index
- radiiArr[index]) {
radiiArr[2 * center - index] = index - center
+ radiiArr[center];
} else {
center = 2 * center - index;
radii = radiiArr[index];
continue loop;
}
}
center = center + radiiArr[center];
radii = 0;
}
}
int radd = radiiArr[maxRadii] / 2;
char[] ch = new char[newStrArr.length / 2];
if (newStrArr[maxRadii] == '0') {
ch = new char[2 * radd];
} else {
ch = new char[2 * radd + 1];
}
for (int i = 0; i < ch.length; i++) {
ch[i] = newStrArr[maxRadii - radiiArr[maxRadii] + 2 * i + 1];
}
return new String(ch);
}
pandm 2011-03-10
  • 打赏
  • 举报
回复
真的很膜拜litaoye,感觉是个算法大牛
knightzhuwei 2011-03-10
  • 打赏
  • 举报
回复

原来如此。。我错了
pandm 2011-03-10
  • 打赏
  • 举报
回复
不懂kmp,里面的那个next数组的构造原理感觉好难理解
华亭真人 2011-03-10
  • 打赏
  • 举报
回复
KMP 改一下就好了吧。

pandm 2011-03-10
  • 打赏
  • 举报
回复
如果str = 123456321
那么str的逆序列 是123654321
他们的最长公共子字符串是123,可是str的最长回文子串长度不是应该是1吗?
绿色夹克衫 2011-03-10
  • 打赏
  • 举报
回复
我以前也犯过同样的错误。

n^2的方法就是枚举每个字符,依次统计回文的长度。
有个近似O(n)的方法,不过真的很复杂,有些类似于dp,到现在我对该方法还是迷迷糊糊的。

[Quote=引用 1 楼 knightzhuwei 的回复:]
输入str
取str的逆序列str2
这时就转化为求str与str2的最长公共子序列的问题 这个有现成算法的吧
[/Quote]
knightzhuwei 2011-03-10
  • 打赏
  • 举报
回复
输入str
取str的逆序列str2
这时就转化为求str与str2的最长公共子序列的问题 这个有现成算法的吧

33,007

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧