POJ3630(Trie树)

这篇博客介绍了如何使用Trie树解决POJ3630题目,即判断给定的多个字符串中是否存在某个串是其他串的前缀。通过在构建Trie树的过程中进行判断,当出现串的前缀是已插入串的情况时,标记为危险节点,并在后续插入中检查。如果满足任一特定条件,答案为NO。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:求给定的多个串中是否存在,某个串是另一个串的前缀。

解题思路:使用Trie树。在每次插入一个串的同时判断。对于该问题,只存在以下两种情况:

 1.当前插入的串的前缀是前面的某个串。对于这种情况,把前面插入的串的最后一个节点记为危险节点。那么在后面插入串的时候,如果经过危险节点,说明这种情况成立。

  2.当前插入的串是前面某个串的前缀。对于这种情况,把插入串的最后一个节点单独拿出来判断,如果该串的最后一个节点已经被分配过地址,则说明这种情况成立。

这两个条件只要满足一个,即回答NO。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstring>

using namespace std;

struct Node
{
    Node * child[10];
    Node *prev;
    bool bad;
    Node()    //构造函数中初始化。在静态分配时就能初始化。
    {
        memset(child, 0, sizeof(child));
        prev = NULL;
        bad = false;
    }
};
int nodeCount;  //用来指向数组中未分配的单元。
bool insertNode(Node *tree, char *s)
{
    int i;
    Node * p = tree;
    for(i = 0; s[i+1]; i++)
    {
        if(p->child[s[i]-'0'] == 0)
        {
            p->child[s[i]-'0'] = tree + nodeCount; //将各个节点按次序分配到数组的相应位置。
            nodeCount++;
        }
        p = p->child[s[i]-'0'];
        if(p->bad)    //如果遇到危险节点(某个字符串的最后一个节点),则说明该串含有前面的串。
        {
            return false;
        }
    }
    bool ok;
    if(p->child[s[i]-'0'] == 0)
    {
         p->child[s[i]-'0'] = tree + nodeCount;
         nodeCount++;    //一开始忘了写这一句,多次WA!!!。
         ok = true;
    }
    else    //如果最后一个节点已经被分配过,说明该串是前面串的前缀。
        ok = false;

    p = p->child[s[i]-'0'];
    p->bad = true;  //字符串最后一个节点是危险节点。
    return ok;
}

int main()
{
    int n, i, t;
    bool ok;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        char s[12];
        Node Tree[100000];  //为了避免初始化,直接重新开,分配大小要合适,否则RA。
        nodeCount = 1;
        ok = true;
        for(i = 0; i < n; i++)
        {
            scanf(" %s", s);
            if(!insertNode(Tree+1, s))
            {
                ok = false;
            }
        }
        if(ok)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值