第一种情况:i<=P
那么找到i相对于po的对称位置,设为j,那么如果Len[j]<P-i,如下图:
那么说明以j为中心的回文串一定在以po为中心的回文串的内部,且j和i关于位置po对称,由回文串的定义可知,一个回文串反过来还是一个回文串,所以以i为中心的回文串的长度至少和以j为中心的回文串一样,即Len[i]>=Len[j]。因为Len[j]<P-i,所以说i+Len[j]<P。由对称性可知Len[i]=Len[j]。
如果Len[j]>=P-i,由对称性,说明以i为中心的回文串可能会延伸到P之外,而大于P的部分我们还没有进行匹配,所以要从P+1位置开始一个一个进行匹配,直到发生失配,从而更新P和对应的po以及Len[i]。
第二种情况: i>P
如果i比P还要大,说明对于中点为i的回文串还一点都没有匹配,这个时候,就只能老老实实地一个一个匹配了,匹配完成后要更新P的位置和对应的po以及Len[i]。
class Solution { public : std::string longestPalindrome(std::string s) { int maxpos = 0, mid = 0; std::vector<int> v; int max = 0; std::string tmp = s; init(tmp); v.resize(tmp.size()); for (int i = 0; i < tmp.size(); ++i) { //如果可以直接从以前计算过的里边取出值 if (i < maxpos) { v[i] = v[mid * 2 - i] < (maxpos - i) ? v[mid * 2 - i] : (maxpos - i); } else { //不能直接从以前计算过的里边取值 v[i] = 1; } //向两遍扩展,寻找以i为中心最长的 while(i - v[i] >= 0 && i + v[i] < tmp.size() && tmp[i - v[i]] == tmp[i + v[i]]) { ++v[i]; } //记录v中最大值的下标,便于函数的最后返回子串 if (v[i] >= v[max]) { max = i; } //更新最大位置和中间位置 if (v[i] + i > maxpos) { maxpos = v[i] + i; mid = i; } } int i, j; //如果max为奇数则表示前边加了v[max]/2+1个# if (max % 2) { i = max / 2 - v[max] / 2 + 1; } else { //max为偶数则表示加了v[max]/2个# i = max / 2 - v[max] / 2; } //v中存储的是预处理后的字符串,减一后表示原字符串的最大回文 j = v[max] - 1; return s.substr(i,j); } private: void init(std::string &s) { s.resize(s.size() * 2 + 1); for (auto i = s.size() - 1; i != 0; i = i - 2) { s[i] = '#'; s[i - 1] = s[(i - 1) / 2]; } s[0] = '#'; } };