计蒜客 习题:糟糕的bug(Trie树)

题目来源:计蒜客https://www.jisuanke.com/minicourse/812/42071

蒜头君作为蒜厂的工程师,在开发网站时不小心写出了一个 Bug:当用户输入密码时,如果既和自己的密码一致,也同时是另一个用户密码的 前缀 时,用户会跳转到 404 页。

然而蒜头君坚称:我们的用户那么少,怎么可能触发这个 Bug……

机智的你,能不能帮蒜头君确认一下这个 Bug 到底会不会触发呢?

样例输入

第一行输入一个整数n(1n233333),表示蒜厂网站的用户数。接下来一共 n 行,每行一个由小写字母a-z组成的字符串,长度不超过 10,表示每个用户的密码。蒜厂的数据库容量太小,所有密码长度加起来小于 466666

样例输出

如果触发了 Bug 则输出一行Bug!,否则输出一行Good Luck!

样例输入1

3
abc
abcdef
cdef

样例输出1

Bug!

样例输入2

3
abc
bcd
cde

样例输出2

Good Luck!


题目类型就是串匹配,找前缀,多串情况下,很应该想到前缀树,也称为Trie树。

这里首先需要把所有串都读下来插入之后再进行匹配,因为你不能确定一定是前面的是后面的前缀。

对cnt处理的时候 也不能像这个Trie树处理一样。本题这里需要找一个串是另一个串的前缀,

所以,应该等一个串读完了,再进行标记。

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

using namespace std;

#define MAX_N 2333430
#define MAX_C 26

struct Trie{
	int *ch[MAX_N];
	int tot;
	int cnt[MAX_N];

	Trie() {
		tot = 0;
		memset( ch, 0, sizeof(ch) );
		memset( cnt, 0, sizeof(cnt) );
	}
	
	void insert( const 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 find( const char* str ) {
		int p = 0;
		for ( int i = 0 ; str[i] ; ++ i ) {
			if ( cnt[p] != 0 && str[i] ) return true; 
			if ( ch[p] == NULL ) return 0;
			if ( ch[p][str[i]-'a'] == -1 ) return 0;
			p = ch[p][str[i]-'a'];
		}
		return false;
	}
};


char s[MAX_N][15];
Trie trie;
int main() 
{
	int n;
	scanf( "%d", &n );
	getchar();
	bool ans = false;
	for ( int i = 0 ; i < n ; ++ i ) {
		scanf( "%s", s[i] );
		getchar();
		trie.insert(s[i]);
	}
	for ( int i = 0 ; i < n ; ++ i ) {
		if ( trie.find(s[i]) ) {
			ans = true;
		}
	}
	if ( ans ) {
		puts("Bug!");
	} else {
		puts("Good Luck!");
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/hopygreat/article/details/79732245