HDU1671 Phone List 题解 字典树

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1671

题目大意,有T组数据,每组数据给你n个长度不超过10的字符串(n不超过10000),问在其中其否存在一个字符串是另一个字符串的前缀。
(我这里把两个相同的字符串也作为前缀了,不过数据应该是没有的)

解题思路:字典树。路径上的点cnt设为1,最后一个点cnt设为2。
如果在路径上碰到了cnt==2的点,或者最后一个点上之前就是cnt>0的。则说明存在前缀。

注意一点:主函数里调用构造函数占用的是栈内存,会MLE。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000010;
struct Trie {
    int son[10], cnt;
    void clean() { //Trie() {
        memset(son, 0, sizeof(son));
        cnt = 0;
    }
} trie[maxn];
int sz;
void init() {
    sz = 0;
    trie[++sz].clean();
}
bool Insert(char *s) {
    int x = 1;
    while (*s) {
        int id = *s - '0';
        if (!trie[x].son[id]) {
            // trie[++sz] = Trie();
            trie[++sz].clean();
            trie[x].son[id] = sz;
        }
        x = trie[x].son[id];
        if (trie[x].cnt == 2) return true;
        s ++;
        if (*s) trie[x].cnt = 1;
        else {
            if (trie[x].cnt != 0) return true;
            else trie[x].cnt = 2;
        }
    }
    return false;
}
char s[10010][11];
int T, n;
int main() {
    scanf("%d", &T);
    while (T --) {
        init();
        scanf("%d", &n);
        for (int i = 0; i < n; i ++) scanf("%s", s[i]);
        bool flag = true;
        for (int i = 0; i < n; i ++) {
            if (Insert(s[i])) {
                flag = false;
                break;
            }
        }
        puts(flag ? "YES" : "NO");
    }
    return 0;
}
posted @ 2020-03-24 22:03  quanjun  阅读(110)  评论(0编辑  收藏  举报