博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
最长回文子串(Manacher算法)
阅读量:4929 次
发布时间:2019-06-11

本文共 2985 字,大约阅读时间需要 9 分钟。

枚举中心位置法:

1 //枚举中心位置法 2 #include
3 #include
4 using namespace std; 5 6 const int MAXN = 1e5; 7 8 int LongestPalindrome(char *s, int len) 9 {10 int i, j;11 if (s == NULL || len < 1)12 return 0;13 int max = 0;14 int c;15 for (i = 0; i < len; i++) //枚举中心位置16 {17 for (j = 0; (i - j >= 0) && (i + j < len); j++) //长度为奇数的情况18 {19 if (s[i - j] != s[i + j])20 break;21 c = j * 2 + 1;22 }23 if (c > max) //更新max24 max = c;25 for (j = 0; (i - j >= 0) && (i + j + 1 < len); ++j) //长度为偶数的情况26 {27 if (s[i - j] != s[i + j + 1])28 break;29 c = j * 2 + 2;30 }31 if (c > max)32 max = c;33 }34 return max;35 }36 int main()37 {38 char s[MAXN];39 while(cin >> s)40 {41 cout << LongestPalindrome(s, strlen(s)) << endl;42 }43 return 0;44 }

 枚举中心位置中,我们需要特别考虑字符串的长度是奇数还是偶数,所以导致我们在编写代码实现的时候要把奇数和偶数的情况分开编写,而Manacher算法则不用分奇偶来讨论

而且上面这种枚举中心位置往两边找的算法时间复杂度是O(n2),下面介绍的“马拉车”算法时间复杂度是O(n)

Manacher算法:

  普通的枚举中心位置的算法需要区分考虑字符串的长度的奇偶性,而Manacher算法则不用区分长度奇偶问题,它的做法是在字符的两边插入一个特殊字符,比如abab转换成#a#b#a#b#,aba转换成了#a#b#a#。为了避免数组越界的问题,还可以在字符串的两端加入特殊的符号。

  Manacher算法使用了一个辅助数组,暂且叫它 P [ ] ,代表的是以 s [ i ] 为中心的最长回文子串往一个方向的拓展长度(这里让它包括 s [ i ] 本身)

  S  #  a  #  b  #  b  #  a  #  b  #  c  #  b  #  a  #

  P  1  2  1  2  5  2  1  4  1  2  1  6  1  2  1  2  1

  观察一下,发现最大的 p [ ] 值减1正好等于原字符串的最长回文子串的长度,所以要知道最长回文子串的长度只需要把 p [ ] 计算出就行了。所以接下来讨论怎么计算p数组

  要计算p数组,先引入几个参数的概念,id:表示目前已知的最长回文子串的中心位置下标;mx:mx = id + p [ id ] ,表示这个回文子串的右边界(即这个回文子串的最右元素的下一位)

  然后核心部分是:如果mx > i,那么P [ i ]  >= min(P [ 2 * id - i ], mx - i)。不理解的话再看看下面两张图就懂了,具体实现看下面代码

 

 

1 #include
2 #include
3 #include
4 using namespace std; 5 6 const int maxn = 1e5 + 10; 7 string s; 8 string new_s; 9 int p[maxn];10 11 string pre(string s) //初始字符的转换12 {13 int len = s.length();14 string ret = "$"; //下标0是$,防止数组越界15 for(int i = 0; i < len; i++)16 {17 ret += "#" + s.substr(i, 1);18 }19 ret += "#@"; //最后加一个符号,防止数组越界20 return ret;21 }22 23 int Manacher()24 {25 new_s = pre(s);26 int len = new_s.length();27 int max_len = -1; //最长回文子串的长度28 int id, mx = 0;29 //算法核心30 for(int i = 1; i < len; i++)31 {32 p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;33 while(new_s[i + p[i]] == new_s[i - p[i]])34 p[i]++;35 if(i + p[i] > mx) //尽可能让mx靠右36 {37 mx = i + p[i];38 id = i;39 }40 max_len = max(max_len, p[i] - 1);41 }42 43 return max_len;44 }45 int main()46 {47 while(cin >> s)48 {49 cout << "s = " << s << endl;50 cout << "new_s = " << pre(s) << endl;51 cout << "max_len = " << Manacher() << endl;52 }53 return 0;54 }

 Reference:

转载于:https://www.cnblogs.com/friend-A/p/9973549.html

你可能感兴趣的文章
JS判断只能是数字和小数点
查看>>
SSL 2289——庆功会
查看>>
Linux命令--su与sudo
查看>>
python课堂练习
查看>>
区块链资料高清PDF合集
查看>>
xml实现AOP
查看>>
bzoj 4237稻草人
查看>>
在发送intent启动activity之前判断是否有activity接收
查看>>
html5特征检测
查看>>
js中几种实用的跨域方法原理详解
查看>>
打印图形
查看>>
《第一行代码》学习笔记7-活动Activity(5)
查看>>
ngx_http_core_module 模块
查看>>
两个常见的oracle索引
查看>>
一位有着工匠精神的博主写的关于IEnumerable接口的详细解析
查看>>
MySQL中特有的函数If函数
查看>>
安装Python3.6.2报错:zipimport.ZipImportError: can't decompress data; zlib not available
查看>>
【蓝桥杯】入门训练 Fibonacci数列
查看>>
实验十 指针2
查看>>
常见HTTP状态码
查看>>