马拉车算法是一个字符串中求最长子字符串,并且此字符串是回文。
本质上是中心扩展法。只是避免有某些多余的计算
核心算法如图所示
假设 已知在A点为中心的回文字符串长度为 E~C段,并且距离上 A-D == D-B
那么,如果我要求 B 点为中心的回文字符串长度,那它肯定等于 D点为中心的回文字符串长度啊。
是的,最核心的就这个了。
剩下的是解决回文字符串长度是奇数还是偶数(利用插入其它字符)
以及如何更新可利用的A点。
附poj 3974 AC代码
int mlc(string &str)
{
if (str.size() == 0) return 0;
string newStr;
newStr.push_back('^');
newStr.push_back('#');
int len = str.size();
for (int i = 0; i < len; i++)
{
newStr.push_back(str[i]);
newStr.push_back('#');
}
newStr.push_back('$');
int newLen = newStr.size();
vector<int> v(newLen,0);
int C = 0, R = 0;
for (int i = 1; i < newLen - 1; i++)
{
int i_mirror = 2 * C - i;
if (R > i)
{
v[i] = min(R - i, v[i_mirror]);
}
else
{
v[i] = 0;
}
while (newStr[i + 1 + v[i]] == newStr[i - 1 - v[i]])
{
++v[i];
}
if (i + v[i] > R)
{
C = i;
R = i + v[i];
}
}
int ret = 1;
for (int i = 1; i < newLen - 1; i++)
{
ret = max(ret, v[i]);
}
return ret;
}
int main()
{
string str;
int idx = 0;
for (; ; )
{
cin >> str;
if (str == "END")
{
break;
}
int len = mlc(str);
cout << "Case " << ++idx << ": " << len << endl;
}
return 0;
}