串首开始的最长回文串长

构造 S = s + "#" + reverse(s),原题就是求S中的前缀等于后缀的最大长度。正是KMP算法预处理pattern求各前缀的最大边界,只要最后返回b[S.size()]。

[kmp算法](http://www.inf.fh-flensburg.de/lang/algorithmen/pattern/kmpen.htm

把前缀等于后缀的部分叫做边界,0<=len(border)<N,求最大边界。

  • 性质1:如果s是x的边界、r是s的边界,r也是x的边界,即边界的边界也是边界
|-r-| |-r-|        |-r-| |-r-| 
|----s----|--------|----s----|
|--------------x-------------|
  • 性质2:r是x的边界,后缀边界和前缀边界后的字符相同,则边界扩展1
|--r--|a               |--r--|a
|-------------x--------------|a

b[i]表示前缀x[0..i-1]的最大边界长。初始设b[0]=-1,空串无边界。假设已解决子问题b[i]b[i-1]等,现在考虑b[i+1]

j=b[i],当x[i]==x[j],由性质2,b[i+1]=j+1;否则,由性质1,继续尝试下一边界j=b[j],直到j=-1,这时刚好b[i+1]=j+1

写法规整后就是维护不变式:i是前缀长、j是边界长

vector<int> buildBorder(const string& pattern) {
	const int M = pattern.size();
	// 设b[i]表示长为i的前缀pattern[0..i-1]的最大边界长
	vector<int> b(M + 1);
	int i = 0, j = -1;  // 空串,无边界
	b[i] = j;
	while (i < M) {
		while (j >= 0 && pattern[i] != pattern[j]) {  // 当前边界不能扩展,性质2
			j = b[j];                                 // 考虑下一小的边界,性质1
		}
		// 扩展边界
		i++, j++;
		b[i] = j;
	}
	return b;
}

int kmp(string pattern, string text) {
	const int N = text.size(), M = pattern.size();
	vector<int> b = buildBorder(pattern);

	int ans = 0;
	int t = 0, p = 0;
	while (t < N) {
		while (p >= 0 && text[t] != pattern[p]) {
			p = b[p];
		}
		t++, p++;

		if (p == M) {
			ans++;     // 匹配成功
			p = b[p];  // 继续寻找下一匹配
		}
	}
	return ans;
}

manacher(马拉车)算法,最长回文串长,O(n)

ref