字符串匹配(KMP、Tire、Map)

KMP

KMP的关键是求出next的值、先预处理出next的值、然后一遍扫过、复杂度O(m+n)

http://acm.hdu.edu.cn/showproblem.php?pid=1711

#include<bits/stdc++.h>
using namespace std;
const int N=1000000+7;
const int M=10000+7;
int n,m;
int a[N],b[M],Next[M];
int kmp()
{
    int i=0,j,k=-1;
    Next[0]=-1;
    while(i<m)
    {
        if(k==-1||b[i]==b[k]) Next[++i]=++k;
        else                  k=Next[k];
    }
    i=0,j=0;
    while(i<n)
    if(a[i]==b[j])
    {
        if(j==m-1) return i-j+1;
        i++,j++;
    }
    else
    {
        j=Next[j];
        if(j==-1) i++,j=0;
    }
    return -1;
}
int main()
{
    int i,j,t,tt=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(i=0;i<n;i++) scanf("%d",&a[i]);
        for(i=0;i<m;i++) scanf("%d",&b[i]);
        if(n<m) {printf("-1\n");continue;}
        printf("%d\n",kmp());
    }
    return 0;
}

Map

map的详细用法  http://blog.csdn.net/sunshinewave/article/details/8067862/

http://acm.hdu.edu.cn/showproblem.php?pid=1880

不Hash超内存,所以使用Map的时候一定要计算好时间和空间

#include<bits/stdc++.h>
using namespace std;
const int N=50000+7;
const int mod=1000000007;
map<string,string> mp1,mp2;
int main()
{
    int i,j,t,tt=0;
    string s;
    while(getline(cin,s))
    {
        if(s=="@END@") break;
        int tmp=s.find(']');
        string from=s.substr(1,tmp-1);
        string to=s.substr(tmp+2,s.size()-1);
        mp1[from]=to;
        mp2[to]=from;
    }
    int n;
    scanf("%d",&n);getchar();
    while(n--)
    {
        getline(cin,s);
        if(s[0]=='[')
        {
            s=s.substr(1,s.size()-2);
            if(mp1.find(s)!=mp1.end()) cout<<mp1[s]<<endl;
            else printf("what?\n");
        }
        else
        {
            if(mp2.find(s)!=mp2.end()) cout<<mp2[s]<<endl;
            else printf("what?\n");
        }
    }
}

Hash

#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <cmath>  
#include <map>  
using namespace std;  
#define debug cout<<"***"<<endl;  
  
map <int,int> m1,m2;  
const int maxn=105000;  
char spell[maxn][100];  
char magic[maxn][100];  
int f1[maxn];  
int f2[maxn];  
int pos1=1,pos2=1;  
unsigned int BKDRHash(char *str)  
{  
    unsigned int seed = 131;  
    unsigned int hash = 0;  
  
    while (*str){  
        hash = hash * seed + (*str++);  
    }  
    return (hash & 0x7FFFFFFF);  
}  
void init(){  
    for(int i=1;i<pos1;i++){  
        m1[BKDRHash(magic[i])]=i;  
        m2[BKDRHash(spell[i])]=i;  
        //f1[BKDRHash(magic[i])]=i;debug;  
        //f2[BKDRHash(spell[i])]=i;  
    }  
}  
int main(){  
  
    memset(f1,-1,sizeof(f1));  
    memset(f2,-1,sizeof(f2));  
    while(scanf("%s",magic[pos1])){  
        if(!strcmp(magic[pos1],"@END@"))  
            break;  
        getchar();  
        gets(spell[pos2]);  
        pos1++;  
        pos2++;  
    }  
    init();  
    int t;  
    scanf("%d",&t);  
    getchar();  
    while(t--){  
        char str[100];  
        gets(str);  
        if(str[0]=='['){  
            int tmp=m1[BKDRHash(str)];  
            if(tmp==0)  
                printf("what?\n");  
            else  
                printf("%s\n",spell[tmp]);  
        }  
        else{  
            int tmp=m2[BKDRHash(str)];  
            if(tmp==0)  
                printf("what?\n");  
            else  
                for(int i=1;i<strlen(magic[tmp])-1;++i)  
                    printf("%c",magic[tmp][i]);  
                printf("\n");  
        }  
    }  
    return 0;  
}

Tire

Trie树用途例子:如何求字符串的所有不同子串 
可以看出将n个模式串插入到一棵单词前缀树的时间复杂度为 O(∑len(i)) ,其中len(i)为第i个模式串的长度。 

C++才能过:http://acm.hdu.edu.cn/showproblem.php?pid=1251

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
const int N=505;
const int inf=0x3f3f3f3f;
struct node{
    int total;
    node *next[30];
    node(){
        memset(next,0,sizeof(next));
        total=0;
    }
};
node *p,*root=new node();
void Insert(char s[]){
    p=root;
    for(int i=0;s[i];i++)
    {
        int x=s[i]-'a';
        if(p->next[x]==NULL)    p->next[x]=new node;
        p=p->next[x];
        p->total++;
    }
}
int Search(char s[]){
    p=root;
    for(int i=0;s[i];i++){
        int x=s[i]-'a';
        if(p->next[x]==NULL) return 0;
        p=p->next[x];
    }
    return p->total;
}
//void Delete(int cnt){
//    p=root;
//    for(int i=0;s[i];i++)
//    {
//        int x=s[i]-'a';
//        p=p->next[x];
//        p->total-=cnt;
//    }
//    for(int i=0;i<30;i++)   p->next[i]=0;
//}
//   int cnt=Search();
//   if(cnt) Delete(cnt);
int main()
{
    char s[33];
    while(gets(s),*s) Insert(s); //一直读入数据,直到遇到空字符串
    while(gets(s))    printf("%d\n",Search(s));
    return 0;
}
trie图是一种DFA,可以由trie树为基础构造出来,  
对于插入的每个模式串,其插入过程中使用的最后一 个节点都作为DFA的一个终止节点。  
如果要求一个母串包含哪些模式串,以用母串作为 DFA的输入,在DFA 上行走,走到终止节点,就意 味着匹配了相应的模式串(没能走到终止节点,并不 意味着一定不包含模式串)。

BZOJ2938 POI2000 病毒 题解&代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 30005;
int n, tot, ch[maxn][2], fail[maxn], danger[maxn], q[maxn], flag, temp, vis[maxn], e[maxn];
char s[maxn];
void addtrie(char s[])
{
    int x = 0, p = 0, len = strlen(s);
    while( p < len )
    {
        temp = s[p]-'0';
        if( !ch[x][temp] ) ch[x][temp]=++tot;
        x = ch[x][temp];
        p++;
    }
    danger[x] = 1;
}
void AC(void)
{
    int h = 0, t = 0;
    for(int i = 0; i < 2; i++)
        if(ch[0][i]) q[t++] = ch[0][i];
    while( h < t )
    {
        temp = q[h++];
        for(int i = 0; i < 2; i++)
        {
            if(!ch[temp][i]) ch[temp][i] = ch[fail[temp]][i];
            else
            {
                fail[ch[temp][i]] = ch[fail[temp]][i];
                danger[ch[temp][i]] |= danger[ch[fail[temp]][i]];
                q[t++] = ch[temp][i];
            }
        }
    }
}
void dfs(int x)
{
    if(flag) return;
    if(x) vis[x] = 1;
    for(int i = 0; i < 2; i++)
    {
        int v = ch[x][i];
        if(vis[v])
        {
            flag = 1;
            return;
        }
        if(e[v] || danger[v])continue;
        e[v] = 1;
        dfs(v);
    }
    vis[x] = 0;
}
int main(void)
{
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        scanf("%s", s);
        addtrie(s);
    }
    AC();
    dfs(0);
    if(flag) printf("TAK\n");
    else printf("NIE\n");
    return 0;
}


例题: POJ2778 DNA Sequence 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值