【ACWing】161. 电话列表

题目地址:

https://www.acwing.com/problem/content/163/

给出一个电话列表,如果列表中存在其中一个号码是另一个号码的前缀这一情况,那么就称这个电话列表是不兼容的。假设电话列表如下:
Emergency 911
Alice 97625999
Bob 91125426
在此例中,报警电话号码(911)为 Bob 电话号码(91125426)的前缀,所以该列表不兼容。

输入格式:
第一行输入整数 t t t,表示测试用例数量。对于每个测试用例,第一行输入整数 n n n,表示电话号码数量。接下来 n n n行,每行输入一个电话号码,号码内数字之间无空格,电话号码不超过 10 10 10位。

输出格式:
对于每个测试用例,如果电话列表兼容,则输出YES。否则,输出NO

数据范围:
1 ≤ t ≤ 40 1≤t≤40 1t40
1 ≤ n ≤ 10000 1≤n≤10000 1n10000

思路是Trie。先将所有字符串插入进去,并且在每个节点维护一个信息 c c c,即多少个单词经过这个节点。接下来再遍历每一个字符串 s s s,如果发现这个字符串沿途的某一个节点的 c c c值等于 1 1 1,则说明没有任何字符串以 s s s为前缀;否则说明 s s s是某个字符串的前缀。这样就能判断出是否存在某个字符串是别的字符串的前缀了。代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1e5 + 10;
int n, son[N][10], cnt[N];
string str[N];
int idx;

void insert(string &s) {
    
    
    int p = 0;
    for (char ch : s) {
    
    
        int u = ch - '0';
        if (!son[p][u]) son[p][u] = ++idx;
        p = son[p][u];
        cnt[p]++;
    }
}

bool query(string &s) {
    
    
    int p = 0;
    for (char ch : s) {
    
    
        int u = ch - '0';
        p = son[p][u];
        if (cnt[p] == 1) return true;
    }

    return false;
}

int main() {
    
    
    int T;
    scanf("%d", &T);
    while (T--) {
    
    
        memset(son, 0, sizeof son);
        memset(cnt, 0, sizeof cnt);
        idx = 0;

        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
    
    
            cin >> str[i];
            insert(str[i]);
        }

        bool flag = true;
        for (int i = 1; i <= n; i++)
            if (!query(str[i])) {
    
    
                flag = false;
                break;
            }

        if (flag) puts("YES");
        else puts("NO");
    }

    return 0;
}

时空复杂度 O ( n ) O(n) O(n)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/121825658