码迷,mamicode.com
首页 > 编程语言 > 详细

【最长回文子串】Manache算法,O(N)时间复杂度

时间:2016-05-07 10:12:49      阅读:1042      评论:0      收藏:0      [点我收藏+]

标签:

问题描述:


找一个字符串里的最长回文子串



暴力法:定中心,从0长度向两端扩展的方法O(n^2), n >= 10^5还是超时,故只能《O(n^2)

Manacher‘s 算法:定中心,从p[r],(已能确定以该点为中心两端是回文的长度开始), 向两端扩展,时间复杂度, O(n)



算法如下:


示意图:

技术分享技术分享技术分享


定义:

cen:当前中心点
p[i]: 以i为中心两端满足回文的长度
r:从0到len-1遍历
l:r关于cen的对称点
绿色:表示已经确定满足回文的部分

步骤:
0. r 遍历 判断是否小于cen+p[cen],是则下一步,否则p[r]=0
1. 确定p[r]已经能确定的大小
    1> 蓝色情况:p[r] = cen+p[cen]-r, 左边的回文长度在边界外
    2> 红色情况:p[r] = p[l],在当前cen+-p[cen]两端边界内
2. 在p[r]的基础上,while(str[r-p[r]]==str[r+p[r]])p[r]++,
    This is the key!!!!!!!p[r]不是都从0开始的
    如果是普通的方法,

    以r为中心,向两端扩展则时间复杂度为O(n^2) 


原理实现:

#include<string>
#include<iostream>
#include<vector>
using namespace std;

void solve(string s) {
	int l, r;
	int len = s.length();
	int cen = 0;
	vector<int> p;
	p.push_back(0);

	for (r = 0; r < len; r++) {
		printf("cen = %d, pcen = %d, r = %d\n", cen, p[cen], r);
		p.push_back(0);
		int cenR = cen + p[cen];
		if (r <= cenR) {
			l = 2 * cen - r;
			p[r] = p[l] < cenR - r ? p[l] : cenR - r;
		} else {
			p[r] = 0;
		}

		// 这里是关键,如果从r为中心长度为0开始向两边扩展,则复杂度为O(n^2), 这里从p[r]开始扩展
		while((r-p[r]-1>=0) && (r+p[r]+1<len) && (s.at(r - p[r] -1) == s.at(r + p[r] + 1))) p[r]++;

		if (r + p[r] >= cenR) {
			cen = r;
		}
	}

	cout << s << endl;
	int i;
	for (i = 0; i < len; i++) {
		printf("%d ", p[i]);
	} printf("\n");
}

int main() {
	solve("11111111111");
	return 0;
}



应用:







【最长回文子串】Manache算法,O(N)时间复杂度

标签:

原文地址:http://blog.csdn.net/zhong123123123/article/details/51329978

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!