【HDU 1247】字典树 一个单词由两个单词组成

来源:互联网 发布:java项目中的角色 编辑:程序博客网 时间:2024/05/18 03:13
#include <iostream>#include <string.h>#include <queue>using namespace std;#define MAX 26struct node;typedef struct node *NumTree;struct node{    int tag;    NumTree ans[MAX];};NumTree init(NumTree T){    int i;    T=new struct node;    for(i=0;i<MAX;i++)    {        T->tag=0;        T->ans[i]=NULL;    }    return T;}void insert(NumTree T,char str[]){    NumTree Q=T,S=NULL;    int len=strlen(str);    int i,id;    for(i=0;i<len;i++)    {        id=str[i]-'a';        if(Q->ans[id]==NULL)        {            S=new struct node;            int j;            for(j=0;j<MAX;j++)            {                S->ans[j]=NULL;                S->tag=0;            }            Q->ans[id]=S;            Q=Q->ans[id];        }        else        {            Q=Q->ans[id];        }    }    Q->tag=1;}int find(NumTree T,char str[]){    NumTree Q=T;    int len=strlen(str);    int i,id;    queue<int>Stack;    for(i=0;i<len;i++)    {        id=str[i]-'a';        if(Q->ans[id]!=NULL)        {            Q=Q->ans[id];        }        if(Q->tag && i<len)//find sepraste point        {            Stack.push(i);        }    }    while(!Stack.empty())    {        int now=Stack.front();        now++;        bool OK=true;        Stack.pop();        Q=T;        while(str[now])        {            id=str[now++]-'a';            if(Q->ans[id]==NULL)            {                OK=false;                break;            }            Q=Q->ans[id];        }        if(OK && Q->tag)            return 1;    }    return 0;}int main(){    char str[50011][20];    NumTree T=NULL;    int x=0;    T=init(T);    while(gets(str[x]) && str[x][0]!='\0')    {        insert(T,str[x]);        x++;    }    int u;    for(u=0;u<x;u++)    {        if(find(T,str[u])==1)            cout<<str[u]<<endl;    }    return 0;}



搞了一下午····

不得不说还是有一些收获,RE的次数最多,

这里要说一下,RE分两种,一种越界,一种是栈溢出,

这里在定义str的时候,

如果定义str[50001][100],就会栈溢出,可见字典树对字符长度的要求很高,不能太长。


整个代码的思路就是在insert同时的时候标记,一个字符如果是一个字符串的结尾字符,那么标记,

在find的时候,如果找到了一个标记,找到了A个标记,说明这个字符串里含有A个字符串,但无法确定这A个字符串是否是紧邻的,这里需要用STACK或者QUEUE,最好还是用STACK,依次记录有标记的下标,然后从后往前开始查询,


这里还有一个小细节,在查询的时候now++,因为top回来的now是一个字符的结尾,重新遍历的时候应该是从找到标记的字符的后一个字符开始。


然后如果有两个以上标记是怎么回事呢?


如果


abcdefg

1001001

有三个标记,这时候从最后一个1开始找,然后从倒数第二个1找,而这里的1代表,至少字典里有a,abcd,abcdefg三个字符串(也可能有defg,bcd等等),也就是说我从标记的下一个字符开始找起,标记的前半部分已经肯定在字符串里了(也就是组成该字符串的前半段),只需要证明从标记开始的字符串也在字典树里,那么就满足该字符串由两个字符串构成,输出即可。



这题还有一个思路,就是把每一个字符串在不同位置“砍一刀”,变成两个字符串,然后find(str1)find(str2),如果都能找到,那么就说明它(这个字符串)有两个字符串构成,这个代码我也实现了,但是不知道为什么一直RE,可能是迭代或者递归的层数太多了(find要递归,如果字符串很长的话,也要砍很多刀)。暂时我还没有想到比较好的优化方案。砍刀也许可以用二分查找实现,但那仍然依赖输入。对效率提升不一定十分明显。


#include <iostream>#include <string.h>using namespace std;#define MAX 26struct node;typedef struct node *NumTree;struct node{    NumTree ans[MAX];};NumTree init(NumTree T){    int i;    T=new struct node;    for(i=0;i<MAX;i++)        T->ans[i]=NULL;    return T;}void insert(NumTree T,char str[]){    NumTree Q=T,S=NULL;    int len=strlen(str);    int i,id;    for(i=0;i<len;i++)    {        id=str[i]-'a';        if(Q->ans[id]==NULL)        {            S=new struct node;            int j;            for(j=0;j<MAX;j++)                S->ans[j]=NULL;            Q->ans[id]=S;            Q=Q->ans[id];        }        else        {            Q=Q->ans[id];        }    }}int find(NumTree T,char str[]){    NumTree Q=T;    int len=strlen(str);    int i,id;    int tag=1;    for(i=0;i<len;i++)    {        id=str[i]-'a';        if(Q->ans[id]!=NULL)            Q=Q->ans[id];        else        {            tag=0;            break;        }    }    return tag;}void FreeTree(NumTree T){    int i;    for(i=0;i<MAX;i++)    {        if(T->ans[i]!=NULL)            FreeTree(T->ans[i]);    }    free(T);}int main(){    char str[50011][100];    NumTree T=NULL;    int x=0;    T=init(T);    while(gets(str[x]) && str[x][0]!='\0')    {        insert(T,str[x]);        x++;    }    int u;    for(u=0;u<x;u++)    {        int i,j,k=1;        int len=strlen(str[u]);        char str1[100],str2[100];        while(k<len)        {            for(i=0;i<k;i++)                str1[i]=str[u][i];            str1[i]='\0';            for(j=0;i<len;i++,j++)                str2[j]=str[u][i];            str2[j]='\0';            if(find(T,str1) && find(T,str2))            {                printf("%s\n",str[u]);                break;            }            k++;        }    }    //FreeTree(T);    return 0;}


0 0
原创粉丝点击