最小最大表示法
用途:用于求最小最大的字符串的编号。
模板:
int getMin(char *s)
{
int i = 0, j = 1, l;
int len = strlen(s);
while(i < len && j < len)
{
for(l = 0; l < len; l++)
if(s[(i + l) % len] != s[(j + l) % len])
break;
if(l >= len)
break;
if(s[(i + l) % len] > s[(j + l) % len])
{
if(i + l + 1 > j)
i = i + l + 1;
else
i = j + 1;
}
else if(j + l + 1 > i)
j = j + l + 1;
else
j = i + 1;
}
return i < j ? i : j;
}
int getMax(char *s)
{
int len = strlen(s);
int i = 0, j = 1, k = 0;
while(i < len && j < len && k < len)
{
int t = s[(i+k)%len]-s[(j+k)%len];
if(!t)
k++;
else
{
if(t > 0)
{
if(j+k+1 > i)
j = j+k+1;
else
j = i+1;
}
else if(i+k+1 > j)
i = i+k+1;
else
i = j+1;
k = 0;
}
}
return i < j ? i : j;
}
字符串哈希
用途:用于字符串查找,每个字符串都有其对应的值
代码:
for(int i=0;i<le;++i)
if(vis[str[i]]==0)
vis[str[i]]=cnt++;
for(int i=0;i<=le-n;++i)
{
int sum=0;
for(int j=0;j<n;++j)
sum=sum*cnt+vis[str[j+i]];
if(has[sum]==0)
{
has[sum]=1;
++ans;
}
}
KMP
用途:字符串快速匹配。
代码:
void GetNext(string P, int next[])
{
int p_len = P.size();
int i = 0; // P 的下标
int j = -1;
next[0] = -1;
while (i < p_len - 1)
{
if (j == -1 || P[i] == P[j])
{
i++;
j++;
next[i] = j;
}
else
j = next[j];
}
}
/* 在 S 中找到 P 第一次出现的位置 */
int KMP(string S, string P, int next[])
{
GetNext(P, next);
int i = 0; // S 的下标
int j = 0; // P 的下标
int s_len = S.size();
int p_len = P.size();
while (i < s_len && j < p_len)
{
if (j == -1 || S[i] == P[j]) // P 的第一个字符不匹配或 S[i] == P[j]
{
i++;
j++;
}
else
j = next[j]; // 当前字符匹配失败,进行跳转
}
if (j == p_len) // 匹配成功
return i - j;
return -1;
}
EX-KMP
用途:字符串T 与 字符串S的每一个后缀 的最长公共前缀。
代码:
const int MAX=100010; //字符串长度最大值
int Next[MAX],extend[MAX];
//预处理计算Next数组
void getNext(char str[])
{
int i=0,j,po,len=strlen(str);
next[0]=len; //初始化next[0]
while(str[i]==str[i+1] && i+1<len) i++; next[1]=i; //计算next[1]
po=1; //初始化po的位置
for(i=2;i<len;i++)
{
if(next[i-po]+i < next[po]+po) //第一种情况,可以直接得到next[i]的值
next[i]=next[i-po];
else //第二种情况,要继续匹配才能得到next[i]的值
{
j = next[po]+po-i;
if(j<0) j=0; //如果i>po+next[po],则要从头开始匹配
while(i+j<len && str[j]==str[j+i]) j++; next[i]=j;
po=i; //更新po的位置
}
}
}
//计算extend数组
void EXKMP(char s1[],char s2[])
{
int i=0,j,po,len=strlen(s1),l2=strlen(s2);
getNext(s2); //计算子串的next数组
while(s1[i]==s2[i] && i<l2 && i<len) i++; extend[0]=i;
po=0; //初始化po的位置
for(i=1;i<len;i++)
{
if(next[i-po]+i < extend[po]+po) //第一种情况,直接可以得到extend[i]的值
ex[i]=next[i-po];
else //第二种情况,要继续匹配才能得到extend[i]的值
{
j = extend[po]+po-i;
if(j<0) j=0; //如果i>extend[po]+po则要从头开始匹配
while(i+j<len && j<l2 && s1[j+i]==s2[j]) j++; extend[i]=j;
po=i; //更新po的位置
}
}
}
Manacher
用途:求最长回文子串
代码:
int Manacher( string s )
{
int maxn = 0;
int po = 0;
int ans = 0;
string str = "@#";
for( int i=0;i<s.size();++i )
{
str += s[i];
str += "#";
}
a[0] = 0;
for( int i=1;i<str.size();++i )
{
if ( maxn > i )
a[i] = min( maxn-i,a[2 * po - i] );
else
a[i] = 1;
while( str[i-a[i]] == str[i+a[i]] )
++a[i];
if ( a[i] + i > maxn )
{
maxn = a[i] + i;
po = i;
}
ans = max( ans,a[i] );
}
return ans-1;
}
字典树
用途:快速查询
struct Trie
{
int v;
Trie *next[26];
Trie(){
v=0;
for(int i=0;i<26;++i)
next[i] = NULL;
}
}*root;
void createTrie(string str)
{
Trie *p = root,*q;
for(int i=0;i<str.length();++i)
{
int id=str[i]-'a';
if(p->next[id] == NULL)
{
q = new Trie();
q->v = 1;
p->next[id] = q;
p=p->next[id];
}
else
{
p = p->next[id];
p->v++;
}
}
}
int findTrie(string str)
{
Trie *p = root;
for(int i=0;i<str.length();++i)
{
int id = str[i]-'a';
p = p->next[id];
if(p == NULL)
return 0;
}
return p->v;
}
AC自动机
用途:是一种多模匹配算法,给你很多个单词,然后给你一段字符串,问你有多少个单词在这个字符串中出现过。
代码:
const int M = 26;
class node{
public:
node *fail;
node *next[M];
int count;
node()
{
count=0;
for(int i=0;i<M;++i)
next[i] = NULL;
}
};
string str;
void insert(node *root,string s)
{
node *p = root;
for(int i=0;i<s.size();i++)
{
int id = s[i]-'a';
if(p->next[id]==NULL)
p->next[id]=new node();
p=p->next[id];
}
p->count ++;
}
void bulidFail(node *root)
{
queue< node* > q;
root->fail=NULL;
q.push(root);
while(!q.empty())
{
node *temp = q.front(),*p;
q.pop();
for(int i=0;i<26;i++)
if(temp->next[i]!=NULL)
{
p=temp->fail;
while(p != NULL)
{
if(p->next[i] != NULL)
{
temp->next[i]->fail = p->next[i];
break;
}
p=p->fail;
}
if(p==NULL)
temp->next[i]->fail = root;
q.push(temp->next[i]);
}
}
}
void find(node *root)
{
int cnt=0;
node *temp = root;
for(int i=0;i<str.size();i++)
{
int id = str[i]-'a';
while(temp->next[id]==NULL && temp != root)
temp = temp->fail ;
temp = temp->next[id];
if(temp == NULL)
temp = root;
node *p = temp;
while(p != root && p->count !=-1)
{
cnt += p->count;
p->count = -1;
p=p->fail;
}
}
cout<<cnt<<endl;
}