• 模板


    KMP - 一对一

    计算next数组的方法是对于长度为n的匹配串,从0到n-1位依次求出前缀后缀最大匹配长度。

    下面的写法是仅仅检测有没有匹配然后返回第一个匹配位置,而不是返回所有匹配位置。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    const int N=100;
    char str[100],ptr[100];//父串str和子串ptr
    int next[100];
    string ans;
    void getnext()//获取next数组
    {
        int i,n,k;
        n=strlen(ptr);
        memset(next,0,sizeof(next));
        k=0;
        for(i=1;i<n;i++)
        {
            while(k>0 && ptr[k]!=ptr[i])
                k=next[k];
            if(ptr[k]==ptr[i]) k++;
            next[i+1]=k;
        //next表示的是匹配长度
        }
    }
    int kmp(char *a,char *b)//匹配ab两串,a为父串
    {
        int i=0,j=0;
        int len1=strlen(a);
        int len2=strlen(b);
        getnext();
        while(i<len1&&j<len2)
        {
            if(j==0||a[i]==b[j])
            {   i++;j++;       }
            else j=next[j+1];//到前一个匹配点
        }
        if(j>=len2)
            return i-j;
        else return -1;
    }
    int main(){
        while( scanf( "%s%s", str, ptr ) )
        {
            int ans = kmp(str,ptr);
            if(ans>=0)
                printf( "%d
    ", kmp( str,ptr ));
            else
                printf("Not find
    ");
        }
        return 0;
    }

    字典树 - 一对多

    其实Trie也叫做前缀树。

    基本性质

    1,根节点不包含字符,除根节点意外每个节点只包含一个字符。

    2,从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。

    3,每个节点的所有子节点包含的字符串不相同。

    优点

    可以最大限度地减少无谓的字符串比较,故可以用于词频统计和大量字符串排序。

      跟哈希表比较:

        1,最坏情况时间复杂度比hash表好

        2,没有冲突,除非一个key对应多个值(除key外的其他信息)

        3,自带排序功能(类似Radix Sort),先序遍历Trie可以得到排序。

    可以用来得到字符串最长公共前缀(转成LCA问题/最近公共祖先问题,用Tarjan算法,dfs某个节点的子树,子树之间的相互的最近公共祖先就是这个节点)

    #include<queue>
    #include<set>
    #include<cstdio>
    #include <iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    /*
        trie字典树
    */
    struct tnode{
        int sum;//用来判断是否是终点的
        tnode* next[26];
        tnode(){
            for(int i =0;i<26;i++)
                next[i]=NULL;
            sum=0;
        }
    };
    tnode *root;
     
    tnode* newnode(){
        tnode *p = new tnode;
        for(int i =0;i<26;i++)
            p->next[i]=NULL;
        p->sum=0;
        return p;
    }
    //插入函数
    void Insert(char *s)
    {
        tnode *p = root;
        for(int i = 0 ; s[i] ; i++)
        {
            int x = s[i] - 'a';
            if(p->next[x]==NULL)
            {
                tnode *nn=newnode();
                for(int j=0;j<26;j++)
                    nn->next[j] = NULL;
                nn->sum = 0;
                p->next[x]=nn;
            }
            p = p->next[x];
        }
        p->sum++;//这个单词终止啦
    }
    //匹配函数
    bool Compare(char *ch)
    {
        tnode *p = root;
        int len = strlen(ch);
        for(int i = 0; i < len; i++)
        {
            int x = ch[i] - 'a';
            p = p->next[x];
            if(p==NULL)
                return false;
            if(i==len-1 && p->sum>0 ){
                return true;
            }
        }
        return false;
    }
    void DELETE(tnode * &top){
        if(top==NULL)
        return;
        for(int i =0;i<26;i++)
            DELETE(top->next[i]);
        delete top;
    }
    int main()
    {
        int n,m;
        cin>>n;
        char s[20];
        root = newnode();
        for(int i =0;i<n;i++){
            scanf("%s",s);
            Insert(s);
        }
        cin>>m;
        for(int i =0;i<m;i++){
            scanf("%s",s);
            if(Compare(s))
                cout<<"YES"<<endl;
            else
                cout<<"NO"<<endl;
        }
        DELETE(root);//看见指针就要想到释放,然而这东西会花时间,所以网上很多人写ACM题就不delete了,我很看不惯这一点。
        return 0;
    }

    AC自动机

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    struct Trie
    {
        int next[210*500][128],fail[210*500],end[210*500];
        int root,L;
    
        int newnode()
        {
            for(int i = 0; i < 128; i++)
                next[L][i] = -1;
            end[L++] = -1;
            return L-1;
        }
    
        void init()
        {
            L = 0;
            root = newnode();
        }
    
        void insert(char s[],int id)
        {
            int len = strlen(s);
            int now = root;
            for(int i = 0; i < len; i++)
            {
                if(next[now][s[i]] == -1)
                    next[now][s[i]] = newnode();
                now=next[now][s[i]];
            }
            end[now]=id;
        }
    
        void build()
        {
            queue<int>Q;
            fail[root] = root;
            for(int i = 0; i < 128; 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 < 128; 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]);
                    }
                }
            }
        }
    
        bool used[510];
        bool query(char buf[],int n,int id)
        {
            int len = strlen(buf);
            int now = root;
            memset(used,false,sizeof(used));
            bool flag = false;
            for(int i = 0; i < len; i++)
            {
                now = next[now][buf[i]];
                int temp = now;
                while(temp != root)
                {
                    if(end[temp] != -1)
                    {
                        used[end[temp]] = true;
                        flag = true;
                    }
                    temp = fail[temp];
                }
            }
            if(!flag)
                return false;
            printf("web %d:",id);
            for(int i = 1; i <= n; i++)
                if(used[i])
                    printf(" %d",i);
            printf("
    ");
            return true;
        }
    };
    char buf[10010];
    Trie ac;
    
    int main()
    {
        int n,m;
        while(~scanf("%d",&n))
        {
            ac.init();
            for(int i = 1; i <= n; i++)
            {
                scanf("%s",buf);
                ac.insert(buf,i);
            }
            ac.build();
    
            int ans = 0;
            scanf("%d",&m);
            for(int i = 1; i <= m; i++)
            {
                scanf("%s",buf);
                if(ac.query(buf,n,i))
                    ans++;
            }
            printf("total: %d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    redis 基本指令
    php 魔术变量
    php 常用函数总结
    linux 命令——3 pwd (转)
    linux 命令——2 cd (转)
    linux 命令——ls
    ffmeg过滤器介绍[转]
    最简单的基于FFMPEG的转码程序 —— 分析
    ffmpga结构体和常用函数(总结)
    leetcode--3
  • 原文地址:https://www.cnblogs.com/Yinku/p/10453621.html
Copyright © 2020-2023  润新知