题意:给你一个字符串问能否拆分为三个回文字符串?能就输出yes,否则输出no。
知识补充:
最长回文子串算法(Manacher算法):
求解最长回文子串的线性时间复杂度算法,主要是通过中心扩展的方法极大地避免了重复计算。实现如下:
- 为了避免对字符串奇偶数的讨论,先对字符串做预处理如下:
规则为在字符间和两边插入‘#‘字符,为了避免越界处理,最两边插入‘^‘和‘$‘字符。
原本字符串为:asd
预处理后为:^#a#s#d#$
- 然后实现部分:
设置两个变量:c 和 r,表示当前最长回文字符串的中心和边界。数组p[max],p[i]表示以i为中心的回文字符串的长度
之后对字符串从左向右处理,有更长的回文字符串就更新c 和 r。这是有如下结论:对于以i为中心的字符串,如果i < r,那么就有:p[i] >= min(p[2 * c - i], r - i)。然后再进行扩展。即可
根据实现后得到的p数组和字符串的对应关系:
#a#s#s#d#
010121010
贴Manacher算法的模板:
Manacher算法:
// 将S转换成T的预处理
// 比如,S = "abba", T = "^#a#b#b#a#$"
// ^和$符号用来表示开始和结束,并且避免边界检查。
string preProcess(string s)
{
int n = s.length();
if (n == 0) return "^$";
string ret = "^";
for (int i = 0; i < n; i++)
ret += "#" + s.substr(i, 1);
ret += "#$";
return ret;
}
string longestPalindrome(string s)
{
string T = preProcess(s);
int n = T.length();
int* P = new int[n];
int C = 0, R = 0;
for (int i = 1; i < n - 1; i++) {
int i_mirror = 2 * C - i; // 等于i‘ = C - (i-C)
P[i] = (R > i) ? min(R-i, P[i_mirror]) : 0;
// 尝试扩展中心为i的回文
while (T[i + 1 + P[i]] == T[i - 1 - P[i]])
P[i]++;
// 如果中心为i的回文超越了R,根据已扩展的回文来调整中心
if (i + P[i] > R) {
C = i;
R = i + P[i];
}
}
// 找出P中的最大值
int maxLen = 0;
int centerIndex = 0;
for (int i = 1; i < n-1; i++) {
if (P[i] > maxLen) {
maxLen = P[i];
centerIndex = i;
}
}
delete[] P;
//返回最大回文子串
return s.substr((centerIndex - 1 - maxLen)/2, maxLen);
}
###这道题的思路:
- 先用Manacher算法处理字符串,把以左端点为起点的回文子串的右端点加入到a数组中,把以右端点为终点的回文子串的左端点加入到b数组中(这里充分利用了Manacher算法处理之后得到的p数组,根据p[i]可以变换出,以i为中心的回文字符串在原串中的起点和终点)。然后枚举左边是a[i]结尾的字符串,和右边是b[j]开始的字符串,再由p数组判断他们中间的那个字符串是否是回文串即可。
- 可以说这个题是Manacher算法的变形,只有充分理解p数组的由来,才可能知道它具有的变形能力。
- 编码时间花费了很久,在动手写代码之前一定要已经思考的非常透彻,毫无逻辑缺陷再动手,这样效率是最高的。
Code:
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iterator>
#include <cmath>
#include <cstring>
#include <cstdlib>
using namespace std;
typedef long long LL;
const int INF = 0x3fffffff, M = 10009;
vector<int> a, b, p;
string preprocess(string s)
{
string ret = "^";
for (int i = 0; i < s.size(); i++) {
ret += "#";
ret += s[i];
}
ret += "#$";
return ret;
}
vector<int> Manacher(string t)
{
vector<int> p;
int R = 0, z = 0;
for (int i = 1; i < t.size() - 1; i++) {
p.push_back(R > i ? min(R - i, p[2 * z - i - 1]) : 0);
while (t[i + p [i - 1] + 1] == t[i - p[i - 1] - 1]) p[i - 1]++;
if (p[i - 1] + i > R) {
z = i;
R = p[i - 1] + i;
}
if (p[i - 1] >= 1) {
int l = (i - 1 - p[i - 1]) / 2+ 1;
int r = (i - 1+ p[i - 1]) / 2;
if (l == 1) a.push_back(r);
if (r == (t.size() - 3) / 2) b.push_back(l);
}
}
return p;
}
bool hw(int x, int y)
{
int temp = y - x - 1;
if (temp <= 0) return false;
if ( p[((x * 2) - 1 + (y * 2) - 1) / 2] >= temp
&& (p[((x * 2) - 1 + (y * 2) - 1) / 2] - temp) % 2 == 0) return true;
return false;
}
int main(void)
{
int t;
cin >> t;
while (t--) {
a.clear();
b.clear();
p.clear();
string s;
cin >> s;
//for (int i = 0 ; i < 100000; i++) s += "as";
bool ans = false;
if (s. size() < 3) { cout << "No" << endl; continue; }
string T = preprocess(s);
p = Manacher(T);
//for (int i = 0; i < p.size() ; i++) cout << p[i] << " ";
for (int i = 0; i < a.size(); i++) {
for (int j = 0; j < b.size(); j++) {
if (a[i] < b[j]) {
int x = a[i];
int y = b[j];
if (hw(x, y)) {
ans = true;
goto l1;
}
}
}
}
l1: if (ans) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-09 03:17:28