码迷,mamicode.com
首页 > 编程语言 > 详细

字符串相关算法合集

时间:2017-12-27 22:37:27      阅读:241      评论:0      收藏:0      [点我收藏+]

标签:质数   return   地方   fine   none   tree   sig   合集   数据结构   

...日后会慢慢补(flag!)先来讲讲基本的

一.字符串Hash

将字符串用一个数表示,常用的写法有:

1.自然溢出

2.单Hash

3.双Hash

前两个会被精心构造的串卡掉,最后一个虽然目前卡不掉,但是出题人可以卡你常数。

所以这个算法很Naive?不是的

我们来看一道题 bzoj1014

用splay维护字符串的最长公共前缀,那么问题来了,没有一种OI比赛中常用的数据结构能维护一个动态的字符串

这时字符串哈希就派上了用场

我们用一个哈希值来表示字符串

在splay上跑一个二分查找就好了

具体的Hash方法网上都有

这里仅介绍思想

技术分享图片
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define ll unsigned long long
#define pi 3.14
#define eps 1e-9
#define inf 2147483233
#define m(a) memset(a,0,sizeof(a))
#define M(a) memset(a,127,sizeof(a))
#define REP(i,m,n) for(int i=1;i<=n;i++)
#define DWN(i,n,m) for(int i=n;i>=1;i++)
#define lowbit(x) x&(-x)
#define POJ(n) while(~scanf("%d",&n) && n)
using namespace std;
int n;
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch==-)f=-1;ch=getchar();}
    while(isdigit(ch)){x=10*x+ch-0;ch=getchar();}
    return x*f;
}
inline void write(int x)
{
    int num=0;
    char buf[15];
    while(x)buf[++num]=(x%10)+0,x/=10;
    while(num)putchar(buf[num--]);
    putchar(\n);
}
ll powe[150000];
void makepow()
{
    int i;
    for(powe[0]=1,i=1;i<140142;i++)powe[i]=powe[i-1]*131;
}
const int maxn=140142;
char str[maxn];
struct SplayTree
{
    int rt,Size;
    int son[maxn][2],f[maxn],size[maxn];
    ll val[maxn],hsh[maxn];
    char s[maxn];
    inline void pushup(int x){size[x]=size[son[x][0]]+size[son[x][1]]+1;hsh[x]=hsh[son[x][0]]+powe[size[son[x][0]]]*s[x]+powe[size[son[x][0]]+1]*hsh[son[x][1]];}
    inline void Rotate(int x,int type)
    {
        int y=f[x];
        son[y][!type]=son[x][type];
        f[son[x][type]]=y;
        f[x]=f[y];
        if(f[x])son[f[y]][son[f[y]][1]==y]=x;  
        son[x][type]=y;
        f[y]=x;
        size[x]=size[y],hsh[x]=hsh[y];
        pushup(y);
    }
    inline void splay(int x,int goal)
    {
        while(f[x]!=goal)  
        {  
            if(f[f[x]]==goal)  
            {  
                if(son[f[x]][0]==x)Rotate(x,1);  
                else Rotate(x,0);  
            }  
            else 
            {  
               int y=f[x],z=f[y];  
               if(son[z][0]==y)  
               {  
                  if(son[y][0]==x)Rotate(y,1),Rotate(x,1);  
                  else Rotate(x,0),Rotate(x,1);  
               }  
               else 
               {  
                   if(son[y][1]==x)Rotate(y,0),Rotate(x,0);  
                   else Rotate(x,1),Rotate(x,0);  
               }  
            }  
        }  
        if(goal==0) rt=x;
    }
    inline int rank(int x,int k)
    {
        if(k<=size[son[x][0]]) return rank(son[x][0],k);  
        else if(k==size[son[x][0]]+1) return x;  
        else return rank(son[x][1],k-size[son[x][0]]-1); 
    }
    inline int build(int l,int r,int id)
    {
        if(l>r)return 0;
        int x=++Size,mid=(l+r)>>1;
        f[x]=id;
        s[x]=str[mid];
        son[x][0]=build(l,mid-1,x);  
        son[x][1]=build(mid+1,r,x);  
        pushup(x);  
        return x;
    }
    inline void insert(int k,char val)  
    {  
        int x=rank(rt,k),y=rank(rt,k+1);  
        splay(x,0),splay(y,x);  
        s[++Size]=val;  
        f[Size]=y,son[y][0]=Size;  
        pushup(Size);  
        pushup(y);  
        pushup(x);  
    }
    inline void change(int k,int val)
    {
        int x=rank(rt,k);  
        splay(x,0);  
        s[x]=val;  
        pushup(x);
    }
    inline int bisearch(int kx,int ky)
    {  
        int l=0,r=n,mid;  
        while(l<=r)  
        {  
            mid=l+r>>1;  
            if(ky+mid>n+2)  
            {  
                r=mid-1;  
                continue;  
            }  
            int x=rank(rt,kx-1),y=rank(rt,kx+mid);  
            splay(x,0),splay(y,x);  
            ll temp=hsh[son[y][0]];  
            x=rank(rt,ky-1),y=rank(rt,ky+mid);  
            splay(x,0),splay(y,x);  
            if(temp==hsh[son[y][0]])l=mid+1;  
            else r=mid-1;  
        }  
        return r;  
    }  
}splay;
int main()
{
    int m,i,j,k,x,y;
    char op[10],val[10];
    scanf("%s%d",str+1,&m);  
    makepow();
    n=strlen(str+1);
    splay.rt=splay.build(0,n+1,0);  
    for(i=1;i<=m;i++)  
    {  
        scanf("%s",op);  
        if(op[0]==I)  
        {  
            scanf("%d%s",&x,val);  
            splay.insert(x+1,val[0]);  
            n++;  
        }  
        else if(op[0]==R)  
        {  
            scanf("%d%s",&x,val);  
            splay.change(x+1,val[0]);  
        }  
        else 
        {  
            scanf("%d%d",&x,&y);  
            if(x>y)  swap(x,y);  
            if(x!=y)  
                printf("%d\n",splay.bisearch(x+1,y+1));  
            else 
                printf("%d\n",n-x+1);  
        }  
    }  
    return 0;  
}
bzoj1014
技术分享图片
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
const int N = 2e6 + 5;
const int seed = 131;
int mod[2] = {1000000007, 1000000009};
char S[N]; //输入字符串
int F[2][N]; //seed ^ a
int pre[2][N];
int n, g, w;
int tim, vis[N], ans[N];
map <pii, int> cnt;

void pre_init(){ //deal with seed ^ n
    for(int t = 0; t <= 1; t++){
        F[t][0] = 1;
        for(int i = 1; i < N; i++){
            F[t][i] = (LL)F[t][i-1] * seed % mod[t];
        }
    }
}

pii Hash(string s){ //Hash a string
    int ret[2] = {0};
    int len = s.size();
    for(int t = 0; t <= 1; t++){
        for(int i = 0; i < len; i++){
            ret[t] = ((LL) ret[t] * seed + s[i]) % mod[t];
        }
    }
    return pii(ret[0], ret[1]);
}

pii Hash(int l, int r)
{
    int ret[2];
    for(int t = 0; t <= 1; t++){
        ret[t] = (pre[t][r] - (LL)pre[t][l-1] * F[t][r-l+1] % mod[t] + mod[t]) % mod[t];
    }
    return pii(ret[0], ret[1]);
}

void pre_solve(){
    int len = strlen(S + 1);
    for(int t = 0; t <= 1; t++){
        pre[t][0] = 0;
        for(int i = 1; i <= len; i++){
            pre[t][i] = ((LL)pre[t][i-1] * seed + S[i]) % mod[t];
        }
        for(int j = len + 1, i = 1; i <= w - 1; i++, j++){
            pre[t][j] = ((LL)pre[t][j-1] * seed + S[i]) % mod[t];
        }
    }
}

bool check(int id){
    tim++;
    int l = id, r = id + w - 1;
    for(int i = 1; i <= n; i++, l += w, r += w){
        pii t = Hash(l, r);
        if(!cnt.count(t)) return 0; //目标串中没有这个子串
        int p = cnt[t];
        if(vis[p] == tim) return 0; //目标串出现了大于1次
        vis[p] = tim; ans[i] = p;
    }
    printf("YES\n");
    for(int i = 1; i <= n; i++) cout << ans[i] <<" "; cout << endl;
    return 1;
}

int main()
{
    pre_init();
    scanf("%d%d%s", &n, &w, S+1);
    pre_solve();
    scanf("%d", &g);
    for(int i = 1; i <= g; i++){
        scanf("%s", S);
        pii t = Hash(S);
        cnt[t] = i;
    }
    bool mark = 0;
    for(int i = 1; i <= w; i++){
        if(check(i)){
            mark = 1;
            break;
        }
    }
    if(mark == 0){
        printf("NO\n");
    }
    return 0;
}
双哈希代码(源网)

模数之一要用19260817这个大质数

有奇效

 

二.K(kan)M(mao)P(pian)

一类用于单字符串匹配的O(n+m)的算法

解释也不是很好讲

直接上模板吧

技术分享图片
#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
int p[101];
int main()
{
    string a,b;
    cin>>a>>b;
    int n=a.length(),m=b.length();
    a=" "+a;b=" "+b;
    int j=0;
    for(int i=2;i<=m;i++)
    {
            while(j>0&&b[j+1]!=b[i])j=p[j];
            if(b[j+1]==b[i])j++;
            p[i]=j;
            }
    j=0;
    for(int i=1;i<=n;i++)
    {
            while(j>0&&b[j+1]!=a[i])j=p[j];
            if(b[j+1]==a[i])j++;
            if(j==m){printf("%d",i-m+1);break;}
            }
    return 0;
}
View Code

 

三.AC自动机

/*多么希望AC和自动能够换一下*/

就是在Trie树上跑KMP

每个点都有一个Fail指针表示如果这个点匹配不上跳到哪个地方

 

四.字符串dp

1.O(n^2)可以过的dp

设计状态一般至少为dp[i][j]表示第一个串的前i个和第二个串的前j个怎么这么样

2.AC自动机上的dp

两种做法:第一个是构建Fail树,跑树形dp

另外一种不能在Fail树上做的,一般有一维表示"当前在AC自动机的x号节点上"

字符串相关算法合集

标签:质数   return   地方   fine   none   tree   sig   合集   数据结构   

原文地址:https://www.cnblogs.com/Kong-Ruo/p/8127695.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!