您的位置:首页 > 其它

几种常用字符串算法

2016-07-10 15:42 302 查看
去年写的,已经发霉,出来晾一晾…

KMP

模式串P在母串S上的匹配。

#define M 100000
int pre[M], n, m;
void set(string p)
{
memset(pre, 0, sizeof(pre));
pre[0] = -1;
int m = p.length();
for(int i = 1;i < m;i++)
{
int j = pre[i-1];
while(j >= 0 && p[j+1] != p[i])
j = pre[j];
pre[i] = p[j+1] == p[i] ? j+1:-1;
}
}
int KMP(string s, string p)
{
set(p);
int j = -1, r = 0, n = s.length(), m = p.length();
for(int i = 0;i < n;i++)
{
while(j >= 0 && s[i] != p[j+1])
j = pre[j];
if(s[i] == p[j+1])
j++;
if(j == m-1)
{
r++;
j = pre[j];
}
}
return r;
}


最小字典序表示

找到一个自循环串的最小表示。

先定义T(i,k)表示一个以i为起点,长为k的串。

环形字符串s复制一遍后接在后面,将环转换为链。

设以T(i,k)为最优解,T(j,k)是待比较的解(i < j)。当k≥N时,匹配完成。

当T(i,k-1) = T(j,k-1),要比较字符s[i+k]与s[j+k]

若s[i+k] = s[j+k],则k++继续往后比较;

若s[i+k] < s[j+k],则T(i,k)为最优,重新给j赋值为j+k+1,不可能更小。

若s[i+k] > s[j+k],则T(j,k)为最优,i←j,j←max(j,i+k)+1,即j只需跳到未被比较过的位置

string smallest(string s, int &ans)
{
int i, j, k, l;
int N = s.length();
s += s;
for(i = 0, j = 1;j < N;)
{
for(k = 0;k < N && s[i+k] == s[j+k];k++);
if(k >= N)
break;
if(s[i+k] < s[j+k])
j += k+1;
else
{
l = i+k;
i = j;
j = max(l, j) + 1;
}
}
ans = i;
return s.substr(i, N);
}


//也可不调换ij
int smallest(string s)
{
int i, j, k, l;
int N = s.length();
s += s;
for(i = 0, j = 1;j < N && i < N;)
{
if(i == j)
j++;
for(k = 0;k < N && s[i+k] == s[j+k];k++);
if(k >= N)
break;
if(s[i+k] < s[j+k])
j += k+1;
else
i += k+1;
}
return min(i, j);
}


长春网络赛1006是求一个串的最大表示方案。可以逆时针和顺时针两种方式。

字典树

复杂度O(N),适合插入与查询。

void insert(char *s, int l, int t, int x)
{
if(t == l)
{
strcpy(a[x].word, s);
a[x].end++;
return;
}
if(a[x].son == 0)
{
size++;
a[x].son = size;
a[size].ch = s[t];
insert(s, l, t+1, size);
return;
}
int i = a[x].son;
if(a[i].ch > s[t])
{
size++;
a[x].son = size;
a[size].next = i;
a[size].ch = s[t];
insert(s, l, t+1, size);
return;
}
int j = i;
while(a[i].ch < s[t] && a[i].next != 0)
{
j = i;
i = a[i].next;
}
if(a[i].ch < s[t])
{
size++;
a[i].next = size;
a[size].ch = s[t];
i = size;
}
else if(a[i].ch > s[t])
{
size++;
a[j].next = size;
a[size].next = i;
a[size].ch = s[t];
i = size;
}
insert(s, l, t+1, i);
return;
}
void read(int x)
{
if(a[x].end)
printf("%s %.4f\n", a[x].word, 100.0*a[x].end/sum);
if(a[x].son)
read(a[x].son);
if(a[x].next)
read(a[x].next);
}


AC自动机

在字典树上的KMP

struct Trie
{
int next[WN][AL], fail[WN], end[WN];
int root, L;
int newnode()
{
for(int i = 0;i < AL;i++)
next[L][i] = -1;
end[L++] = 0;
return L-1;
}
void init()
{
L = 0;
root = newnode();
}
void insert(char buf[], int x)
{
int len = strlen(buf);
int now = root;
for(int i = 0;i < len;i++)
{
if(next[now][buf[i]-'A'] == -1)
next[now][buf[i]-'A'] = newnode();
now = next[now][buf[i]-'A'];
}
end[now] = x;
}
void build()
{
queue<int> Q;
fail[root] = root;
for(int i = 0;i < AL;i++)
if(next[root][i] == -1)
next[root][i] = root;
else
{
fail[next[root][i]] = root;
Q.push(next[root][i]);
}
while(!Q.empty())
{
int now = Q.front();
Q.pop();
for(int i = 0;i < AL;i++)
if(next[now][i] == -1)
next[now][i] = next[fail[now]][i];
else
{
fail[next[now][i]] = next[fail[now]][i];
Q.push(next[now][i]);
}
}
}
int query(char buf[])
{
int len = strlen(buf);
int now = root;
int res = 0;
for(int i = 0;i < len;i++)
{
now = next[now][buf[i]-'A'];
int temp = now;
while( temp != root )
{
res += end[temp];
end[temp] = 0;
temp = fail[temp];
}
}
return res;
}
}ac;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: