zoukankan      html  css  js  c++  java
  • Trie字典树

    loj.ac 10049

    代码1:Trie树+指针实现

    时间复杂度:O(TN10),每个字符串长度最大为10,在树上插入一个字符串最多10步。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int  T, flag;																			//flag为有前缀标记 
    char s[11];
    struct node{ int end; node *nxt[10]; node(){end=0; memset(nxt, 0, sizeof(nxt));} }*root;//root为根指针,使用链式前向星会降低查找效率 
    void insert(char *s)
    {
    	bool ret=false; node *r=root; int l=strlen(s);
    	for(int i=0; i<l; i++)
    	{
    		int id=s[i]-'0';
    		if(r->nxt[id]==NULL)	r->nxt[id]=new node();
    		else if(i==l-1 && r->nxt[id]->end==0)	flag=1;									//最后一个字符结点已经存在且没有结束标记,说明s是某字符串的前缀 
    		r=r->nxt[id];
    		if(i<l-1 && r->end)		flag=1;													//走过的路径上(当前s还未结束)发现了结束标记,存在前缀 
    		if(i==l-1)	r->end=1;															//打单词结束标记 
    	}
    } 
    void clearTree(node * &t)																//递归清除树 
    {
    	if(!t)	return;
    	for(int i=0; i<10; i++)
    		if(t->nxt[i])	clearTree(t->nxt[i]);
    	delete t;
    	t=NULL; 
    }
    int main()
    {
    	scanf("%d", &T);
    	while(T--)
    	{
    		root=new node();
    		flag=0;
    		int n;
    		scanf("%d", &n);
    		for(int i=1; i<=n; i++)
    		{
    			scanf("%s", s);
    			insert(s);
    		}
    		if(flag)	printf("NO
    ");
    		else		printf("YES
    ");
    		clearTree(root);																//清空树
    	}
    	return 0;
    } 
    

    代码2:sort+贪心

    时间复杂度:O(T(NlgN+10N)),排序为NlgN,每个字符串长度最大为10,每次查找字串最多10步,共查找N-1次。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    string s[10001];
    int main()
    {
        int T, n;
        cin>>T;
        while(T--)
        {
            bool flag=false;
            cin>>n;
            for(int i=1; i<=n; i++)	cin>>s[i];
            sort(s+1, s+n+1);								//排序所有字符串 
            for(int i=1; i<=n-1; i++)
            {
                if(s[i+1].find(s[i], 0)==0)					//后一项中查找前一项是否是其子串,这里使用find会带来性能的降低,find会从0号位置之后的所有可能位置进行匹配,建议手打查找,仅从0号位置匹配。
                {
                    flag=true;
                    break;
                }
            }
            if(flag) 	printf("NO
    ");
            else 		printf("YES
    ");
        }
        return 0;
    }
    

    代码3:Trie树+数组实现1

    非原创,代码来源:https://yuzhechuan.blog.luogu.org/solution-sp4033

    时间复杂度:同代码1

    #include <iostream>
    #include <cstdio>
    #include <cstring> //没打万能头是因为我先在poj交的,你懂的。。。
    using namespace std;
    int t,n,tot;
    bool flag;
    struct node{ //trie树节点
        int go[10];
        bool end;
    }a[100005];
    inline void ins(char *s){
        if(flag) return ; //flag=1表示有符合条件的情况且已被找到所以可以尽管跳过
        int x=0,l=strlen(s+1);
        for(int i=1;i<=l;i++){ //遍历每个数字
            int k=s[i]-'0';
            if(!a[x].go[k]) a[x].go[k]=++tot;
            else if(i==l) flag=1; //第一种情况判断:如果1个串的末尾在trie树中已被定义,则它定是前面某个串的前缀
            x=a[x].go[k];
            if(a[x].end) flag=1; //第二种情况判断:如果1个串中的某个字符是前面某个串结尾点,则前面定有一个串是它的前缀
        }
        a[x].end=1;//标记末尾节点
    }
    int main(){
        scanf("%d",&t);
        while(t--){
            flag=tot=0;
            memset(a,0,sizeof a); //全部清0
            scanf("%d",&n);
            for(int i=1;i<=n;i++){
                char c[15];
                scanf("%s",c+1); //我习惯从下标1开始存
                ins(c); //插入trie树
            }
            if(flag) puts("NO"); //注意反着输
            else puts("YES");
        }
    }
    

    代码4:Trie树+数组实现2(更有技巧地使用数组)

    非原创,代码来源:https://www.luogu.org/blog/Maroon5andLogan/solution-sp4033

    时间复杂度:O(TNZ),N是结点个数,Z是字符集大小(10)。结点个数考虑极限情况,所有的字符串的字符都自成一个结点,每个字符串长度最大为10,所以结点N为n(10^4)*10,这里定义N=100005。

    #include<bits/stdc++.h>
    using namespace std;
    #define RN register int
    const int N=1e5+5;
    const int Z=10;
    int T,n,tot;
    int ch[N][Z];//表示该节点的字符指针指向的节点,若为0,则无子节点
    bool bo[N];
    char s[20];
    inline bool insert(char *s)//插入串,并判断.
    {
        int len=strlen(s);
        int u=1;
        bool flag=false;
        for(RN i=0;i<len;i++)
            {
                int c=s[i]-'0';
                if(!ch[u][c])//如果当前这个节点u没有指向c的指针,则建立一个
                    ch[u][c]=++tot;
                else if(i==len-1)//如果搜完了,没有插入任何的新节点,则说明该串出现过,第1种情况
                    flag=true;
                u=ch[u][c];
                if(bo[u])//如果经过某个有标记的节点,属于第2种情况
                    flag=true;
            }
        bo[u]=true;
        return flag;
    }
    int main()
    {
    
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            tot=1;//新建一个Trie树,其根节点为1
            memset(ch,0,sizeof(ch));
            memset(bo,false,sizeof(bo));//每次都要初始化
            bool ans=false;
            for(RN i=1;i<=n;i++)
            {
                scanf("%s",s);
                if(insert(s))
                    ans=true;
    
            }
            if(!ans)//注意不要写反
                puts("YES");
            else
                puts("NO");
        }
        return 0;
    }
    

    Luogu P2292 L语言

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int n, m, dp[1100000];									//dp[x]=1说明前x个可以被理解 
    char word[11], text[1100000];
    struct node{ int end; node* nxt[26]; node(){end=0; memset(nxt, 0, sizeof(nxt));}}*root;
    void insert(char *s)
    {
    	node *r=root; int l=strlen(s);
    	for(int i=0; i<l; i++)
    	{
    		int id=s[i]-'a';
    		if(r->nxt[id]==NULL)	r->nxt[id]=new node();
    		r=r->nxt[id];
    		if(i==l-1)	r->end=1; 
    	}
    }
    void search(char *t, int pos)							//从pos位置开始匹配 
    {
    	node *r=root;
    	while(t[pos]!='')
    	{
    		int id=t[pos]-'a';
    		if(r->nxt[id]==NULL)	return;
    		r=r->nxt[id];
    		if(r->end)	dp[pos]=1;							//此位置有单词结束标记,标记pos位置待以后转移 
    		pos++;
    	}
    }
    int main()
    {
    	cin>>n>>m;
    	root=new node();
    	for(int i=1; i<=n; i++)	cin>>word, insert(word);
    	for(int i=1; i<=m; i++)
    	{
    		cin>>(text+1);
    		memset(dp, 0, sizeof(dp));						//清空dp数组 
    		dp[0]=1;										//初始条件,前0个字符可匹配 
    		int len=strlen(text+1);
    		for(int i=0; i<len; i++)
    		{
    			if(!dp[i])	continue;
    			search(text, i+1); 
    		}
    		int ans;
    		for(ans=len; ans>0; ans--)	if(dp[ans])	break;	//倒序查找最大匹配位置 
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    7.19 repeater的用法:
    7.18 内置对象
    7.17 三级联动 控件及JS简单使用
    7.15 简单控件 以及 复合控件
    7.14 Repeater
    7.14 ASP.NET介绍 基础
    phpcms图文总结(转载)
    phpcms图文总结(转)
    商业php软件的应用
    php前段时间复习
  • 原文地址:https://www.cnblogs.com/lfyzoi/p/10898746.html
Copyright © 2011-2022 走看看