杭电1671——Phone List(字典树的应用)

原题链接

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

问题分析

该题需要我们判断字符串中是否有字符串是其他字符串的前缀。本题中使用了字典树,字典树结构对处理字符串前缀问题非常方便。主要考虑一下三种情况:
(1)以前插入的字符串是当前字符串的前缀:比如,之前向字典树中插入字符串“911”,当前插入的字符串为“9110”。当前字符串“9110”插入第三个字符‘1’的时候,发现该节点的v值为’1’,表示某个字符串的结尾。直接返回0,不再插入字符(也不会存在新建节点),输出NO。
(2)当前插入的字符串为以前插入的字符串的前缀:比如,以前插入字符串“9110”,当前插入的字符串为“911”。此时,设置一个变量isOk,初始值为0,只有当新建节点的时候,isOk才会为1。很明显,当前插入“911”并不需要新建节点,知道插完最后一个字符’1’,isOk的值还为0,此时返回isOk,表示不一致,输出NO。
(3)不存在前缀,插入字符串过程中新建节点,isOk=1,输出YES。

注意:一个案例判断完毕后要释放这个案例的字典树占用的内存,否则,会超出内存范围。

AC代码

# include<stdio.h>
# include<string.h>
# include<malloc.h>
# define MAX 10

typedef struct Trie{
    struct Trie * next[MAX];
    char v;//若为'1',表示为字符串的最后一个字符,否则为字符串的中间字符
}Trie;

int isConsistent(Trie ** root,char num[]);
void myfree(Trie ** root);

int main()
{
    char num[11];
    int t,n,i;
    Trie * root;
    scanf("%d",&t);
    while(t--)
    {
        root=NULL;
        int flag=1;
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%s",num);
            if(flag)
            {
                flag=isConsistent(&root,num);
            }
        }
        if(flag)
            printf("YES\n");
        else
            printf("NO\n");
        myfree(&root);
    }
    return 0;
}

//判断某个字符串是否为另一个字符串的前缀。若是,则返回0,否则,返回1.
int isConsistent(Trie ** root,char num[])
{
    int i,len=strlen(num),j;
    //isOk只有在插入新节点的时候才会为1.如果一直都没有插入新节点,
    //说明该字符串是前面某个字符串的前缀。比如,前面插入字符串"9110",
    //现在的字符串为“911”,此时不需要新建节点,只需一步一步向下遍历既可。
    //遍历完"911"之后,isOk仍然为0.
    //如果在遍历的过程中遇到某个字符串的最后一个字符,比如“91”的'1',则
    //会直接返回0,不会再继续插入"911"的最后一个'1'.
    int isOk=0;
    if(*root==NULL)
    {
        *root=(Trie *)malloc(sizeof(Trie));
        for(i=0;i<MAX;i++)
            (*root)->next[i]=NULL;
        (*root)->v='0';
    }
    Trie *p=*root;
    for(i=0;i<len;i++)
    {
        int id=num[i]-'0';
        if(p->next[id]==NULL)
        {
            p->next[id]=(Trie *)malloc(sizeof(Trie));
            p=p->next[id];
            p->v='0';
            isOk=1;
            for(j=0;j<MAX;j++)
                p->next[j]=NULL;
        }
        else
        {
            p=p->next[id];
            if(p->v=='1')
                return 0;//前面插入的字符串中存在该字符串的前缀,比如说,前面插入字符串"911",现在插入的字符串为“9110”。
        }
    }
    p->v='1';
    return isOk;
}

void myfree(Trie ** root)
{
    Trie *p=*root;
    int i;
    for(i=0;i<MAX;i++)
    {
        if(p->next[i]!=NULL)
        {
            myfree(&(p->next[i]));
        }
    }
    free(p);
    p=NULL;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值