- 字典树
字典树的概念:
字典树是一棵树,字符在边上,一条路径上的全部字符构连成一个字符串。字典树是用来处理多串问题的,主要是用来查找,还可以求两个串的lcp(最长公共前缀)。
struct Trie
{
int tot, ch[maxn][26], end[maxn];
void init(){while(tot--)cl(ch[tot+1]),end[tot+1]=0;tot=1;}
int append(int pos, int c)
{
int &t=ch[pos][c];
return t?t:t=++tot;
}
int insert(char* s, int n)
{
int pos=1, i;
for(i=1;i<=n;i++)pos=append(pos,id(s[i]));
end[pos]++;
return pos;
}
}trie;
- KMP算法
- KMP算法的核心思想是避免匹配失败时重新从短串的第一个字符开始匹配,从而提高匹配效率。
应用:字符串匹配问题,和循环节有关的问题。
#include <iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstring>
#include <string>
typedef long long ll;
using namespace std;
//未改进的KMP算法代码实现
void get_next(int *next, char *T, int len)
{
next[0] = -1;//-1代表没有重复子串
int k = -1;
for (int q = 1; q <= len; q++)
{
while (k > -1 && T[k+1] != T[q])//下一个元素不相等,把k向前回溯
{
k = next[k];
}
if (T[k+1] == T[q])//下一个元素相等,所以最长重复子串+1
{
k = k+1;
}
next[q] = k;//给next数组赋值
}
}
int KMP(char *s, int len, char *p, int plen)//利用KMP算法匹配
{
int *next = new int(plen);
get_next(next, p, plen);
int k = -1;
int i = 0;
for (; i < len; i++)
{
while (k > -1 && p[k+1]!=s[i])//两串下一个字符不相等,向前回溯(效率高就是在这里,每次匹配失败,k不用直接变为0,从第一个字符开始重新匹配,而是变为最长重复子串的下一个字符,从中间开始匹配即可)。
{
k = next[k];
}
if(p[k+1] == s[i])//两个串的字符相等,k+1来匹配子串的一个字符
{
k++;
}
if (k == plen-1)//匹配成功,返回短串在长串的位置。
{
return i-plen+1;
}
}
return -1;
}
int main()
{
char a[] = "bacbababadababacambabacaddababacasdsd";
char b[] = "ababaca";
int m = KMP(a,strlen(a),b,strlen(b));
printf("%d", m);
return 0;
}
其它算法科普
后缀自动机(SAM),是一种十分好用,效率又很高的字符串处理算法。SA能解决的问题,它基本上都能解决,不过它使用的数学知识比较高级,不像SA那么容易理解。如果把它扩展到字典树上,就可以处理多串问题,被称作“广义后缀自动机”。
AC自动机,就是把kmp的相关理论搬到字典树上,从而用以解决多串匹配问题。manacher,回文自动机。这两种算法用以处理回文串问题。
后缀平衡树,通过平衡树来维护sa序列,以及动态计算height。时间复杂度较高,应用场合很少。
摘自基地王大佬