目录
//给定一个字符串,尽可能的少添加字符使其整体构成一个回文串
1、给出N 个单词组成的熟词表,以及一篇全用小写英文书写的文章; 将n个单词建立成字典树; 这一大串字符串到字典树中找
1、KMP(自匹配,且只与开头比较)
#include<bits/stdc++.h>
using namespace std;
int nextt[15];
void prenext(string s)
{
int len = s.length();
int j = 0;
nextt[0] = 0;
for(int i = 1; i<len; i++) ///由于第一个字符肯定next为0(因为最大公共前后缀不能为本身),所以从1开始
{
while(s[i]!=s[j]&&j!=0) j = nextt[j-1];///j=0跳出循环
if(s[i]==s[j]) j++;
nextt[i] = j;
}
}
2、kmp(两个字符串匹配,来找出最长公共字符串)
#include<stdio.h>
#define N 100010
#define M 100010
char p[N],s[N];
int n,m;//n是子串的长度,m是主串的长度
int ne[N];//next数组
int main()
{
scanf("%d%s%d%s",&n,&p,&m,&s);
//求next数组的过程
ne[0]=0;
for (int i = 1, j = 0; i < n; i++)//下标从0开始
{
while (j&& p[i]!= p[j]) j = ne[j-1];//求字串的next数组,j指向子串的起始位置,i指向子串的起始位置的下一个位置
if (p[i] == p[j]) j++;//如果相等,j指向子串的下一个位置
ne[i] = j;//子串中下标为i的字符前的字符串最长相等前后缀的长度为j
}
int maxx=-1;
for (int i = 0, j = 0; i <m; i++)//i的话是遍历一遍主串的所有字母,j是从子串每次从零开始遍历,看能不能匹配成功,
{
while (j && s[i] != p[j])//j未回到起点,并且长串里的s[i]和短串里的p[j]匹配失败
{
j = ne[j-1];//把j移到next[j-1]的位置。
}
if (s[i] == p[j ]) j++;
if (j == n)//j走到子串的头了
{
printf("binggo");
}
else
{
maxx=max(maxx,j);
}
}
return 0;//时间复杂度为O(n)
}
//
#include<bits/stdc++.h>
using namespace std;
#define MAXX 1000000
int tnext[MAXX];
int snext[MAXX];
void kmp(string s,string t)
{
tnext[0]=0;
snext[0]=0;
int maxx=-1;
int j=0;
for(int i=1;i<t.length();i++)
{
//若一开始不匹配即j==0,会一直0下去
//所以不匹配要在j!=0下,回前看:
while(j&&t[i]!=t[j])j=tnext[j-1];
if(t[i]==t[j])j++;
tnext[i]=j;
}
for(int i=0,j=0;i<s.length();i++)
{
while(j&&s[i]!=t[i])j=tnext[j-1];
if(s[i]==t[j])j++;
snext[i]=j;
maxx=max(maxx,j);
if(maxx==t.length())
{
cout<<"binggo";
break;
}
}
if(maxx!=t.length())
{
cout<<maxx<<endl;
}
}
3、马拉车算法
//给定一个字符串,尽可能的少添加字符使其整体构成一个回文串
//有多少个回文子串(输出以其为开头的最长即可)
#include <iostream>
using namespace std;
string s;
char help[100];
int n;
int search(int index, int step){
int res = 1 + 2 * step;
int L = index - 1 - step;
int R = index + 1 + step;
while(L >= 0 && R <= 2 * n){
if(help[L] != help[R])
break;
L--, R++;
res += 2;
}
return res/2;
}
int getMax(){
int max = 0;
for(int i = 0; i < 2*n+1; i++){
int temp = search(i, 0);
//cout << temp << endl;
max= temp > max ? temp : max;
}
return max;
}
int *manacher(){
int *res = new int[2*n+1];
int R = -1, L;
int C, imageCur, imageL;
int cur = 0, curR;
while(cur < 2*n+1){
if(cur > R){
C = cur;
curR = search(cur, 0);
R = R + curR + 1;
res[cur] = curR;
}else{
imageCur = 2 * C - cur;
L = 2 * C - R;
imageL = imageCur - res[imageCur];
if(imageL > L){
res[cur] = res[imageCur];
}else if(imageL < L){
res[cur] = R - cur;
}else if(imageL == L){
curR = search(cur, R - cur);
if(cur + curR > R){
C = cur;
R = cur + curR;
}
res[cur] = curR;
}
}
cur++;
}
return res;
}
void input(){
cin >> s;
n = s.length();
for(int i = 1; i < 2*n+1;){
help[i] = s[(i-1)/2];
help[i-1] = '#';
i += 2;
}
help[2*n] = '#';
for(int i = 0; i < 2*n+1;){
cout << help[i] << " ";
i ++;
}
cout << endl;
}
void printSub(int C, int R){
for(int i = C - R + 1 ; i < C+ R;){
cout << help[i];
i += 2;
}
cout << endl;
}
void printAllSub(int res[]){
for(int i = 1; i < 2*n+1; i++){
if(res[i] > 1)
printSub(i, res[i]);
}
}
//给定一个字符串,尽可能的少添加字符使其整体构成一个回文串
int *getMin(){
int *res = new int[2*n+1];
int R = -1, L;
int C, imageCur, imageL;
int cur = 0, curR;
while(cur < 2*n+1){
if(R == 2*n) break;
if(cur > R){
C = cur;
curR = search(cur, 0);
R = R + curR + 1;
res[cur] = curR;
}else{
imageCur = 2 * C - cur;
L = 2 * C - R;
imageL = imageCur - res[imageCur];
if(imageL > L){
res[cur] = res[imageCur];
}else if(imageL < L){
res[cur] = R - cur;
}else if(imageL == L){
curR = search(cur, R - cur);
if(cur + curR > R){
C = cur;
R = cur + curR;
}
res[cur] = curR;
}
}
cur++;
}
return new int[2] {C, res[C]};
}
void printSuffix(int C, int R){
int length = 0;
printSub((2*n+1)/2, (2*n+1)/2);
for(int i = C - R - 1; i >= 1;){
cout << help[i];
i -= 2;
length++;
}
cout << " " << length << endl;
}
//给定一个字符串,尽可能的少添加字符使其整体构成一个回文串
int main()
{
input();
cout << "The longest sub-string length is : " << getMax() << endl;
int *res = manacher();
for(int i = 0; i < 2*n+1; i++){
cout << res[i] << " " ;
}
cout << endl;
printAllSub(res);
return 0;
}
输出所有回文子串(向中心扩展)
void expand(string str, int low, int high, auto &set)
{
// 运行直到 `str[low.high]` 不是回文
while (low >= 0 && high < str.length() && str[low] == str[high])
{
// 将是回文推入一个集合
set.insert(str.substr(low, high - low + 1));
// 从中心向两边展开
low--,high++;
}
}
// 查找给定字符串的所有唯一回文子串的函数
void findPalindromicSubstrings(string str)
{
// 存所有唯一的回文子串
unordered_set<string> set;
for (int i = 0; i < str.length(); i++)
{
// 所有以 `str[i]` 为中点的奇数回文数
expand(str, i, i, set);
// 所有偶数长度的回文 // 它的中点
expand(str, i, i + 1, set);
}
// 打印所有唯一的回文子串
for (auto i: set) {
cout << i << " ";
}
4、多个字符串匹配(字典树)
1、给出N 个单词组成的熟词表,以及一篇全用小写英文书写的文章; 将n个单词建立成字典树; 这一大串字符串到字典树中找
2、多个字符串的公共前缀 建字典树;找最近公共祖先
void insert(const string& s,int index_of_s){
int r = 0;
for(int i=0;i<s.size();++i){
int idx = s[i] - 'a';
int& next = childs[r][idx];
//printf("%d %d %d %d\n",r,idx,next,nodes_cnt);
if(next == 0){
next = ++nodes_cnt;
}
r = next;
}
values[r] = index_of_s;
}
void find(const string & t,int beg,vector<vector<int>>& ans){
int r = 0;
for(int j = beg;j < t.size();++j){
int idx = t[j] - 'a';
const int& next = childs[r][idx];
if(next == 0){//没找到
return ;
}
if(values[next] >= 0){//t[beg,j]是一个串,记录开始位置beg
ans[values[next]].push_back(beg);
}
r = next;
}
}
};