糟糕的Bug

题目描述
小明作为工厂的工程师,在开发网站时不小心写出了一个 Bug:当用户输入密码时,如果既和
自己的密码一致,也同时是另一个用户密码的 前缀 时,用户会跳转到 404 页。然而小明坚称:
我们的用户那么少,怎么可能触发这个 Bug……
 机智的你,能不能帮小明确认一下这个 Bug 到底会不会触发呢?  样例输入:第一行输入一个整数 n(1≤n≤233333),表示工厂网站的用户数。接下来一共 n行,
每行一个由小写字母a-z组成的字符串,长度不超过 10,表示每个用户的密码。工厂的数据库
容量太小,所有密码长度加起来小于 466666。
 样例输出:如果触发了 Bug 则输出一行Bug!,否则输出一行Good Luck!。
 样例输入1
 3
 abc
 abcdef
 cdef
 样例输出1
 Bug!
 样例输入2
 3
 abc
 bcd
 cde
 样例输出2
 Good Luck!

初步分析
这道题如果用朴素算法的话,如果有n个字符串则公有n*(n-1)种匹配方式所以暴力求解的平均复杂度大概是O(m*n^2)。肯定会被一些大的数据卡主的。而如果采用trie数的话,复杂度会直接降到线性级别O§.p是Trie树里的节点个数。那么怎么检测一个字符串是否其他字符串的前缀呢?其实很简单,我们只需要深度优先搜索Trie树(按从小到大的方式),值达到叶节点终端检查前面的路径是否出现过终端点(用flag来做标记)。

直接上代码

#include <iostream>
#include <string.h>
using namespace std;
const int MAX_N=233334;
const int MAX_C=26;
typedef struct trie {
    int *ch[MAX_N];
    int tot;
    int cnt[MAX_N];

    void init() {
        tot = 0;
        memset(ch, NULL, sizeof(ch));
        memset(cnt, 0, sizeof(cnt));
    }

    void insert(char *str) {
        int p = 0;
        for (int i = 0; str[i]; ++i) {
            if (ch[p]==NULL){
                ch[p]=new int[MAX_C];
                memset(ch[p],-1, sizeof(int)*MAX_C);
            }

            if(ch[p][str[i]-'a']==-1){
                ch[p][str[i]-'a']=++tot;
            }
            p=ch[p][str[i]-'a'];
        }
        cnt[p]++;
    }

    bool stop= false;

    void dfs(int p,int flag1){
        if(stop)
            return ;

        if(cnt[p]>0){
            if(flag1==1){
                stop= true;
                return;
            }
            flag1=1;
        }

        if(ch[p]!=NULL){
            for(int i=0;i<26;++i){
                if(ch[p][i]!=-1){
                    dfs(ch[p][i],flag1);
                }
            }
        }
    }
}Trie;
int main() {
    int n;
    cin>>n;
    Trie arr;
    arr.init();
    for(int i=0;i<n;++i){
        char temp[20];
        scanf("%s",temp);
        arr.insert(temp);
    }

    arr.dfs(0,0);
    if(arr.stop)
        cout<<"Bug!"<<endl;
    else
        cout<<"Good luck"<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值