字典树入门

字典树

给出N个字符串,再给出M个查询,每个查询给出一个字符串,求这个字符串在给出的N个字符串中有没有出现过。
在这里插入图片描述

暴力做法:

遍历一遍给出的字符串数组,比较两个字符串是否相等。

复杂度为O(N*len)

使用map的做法:

将字符串保存入map中,询问时判断映射的值

复杂度为O(logN*len)

使用hash的做法:

完全不冲突复杂度为O(1),完全冲突复杂度为O(N)

字典树

介绍:
Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种hash表的变形。典型应用是用于存储 、统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎用于文本词频统计。
是一种快速检索的多叉树结构,如英文字母的字典树是一个26叉树或52叉树,数字的字典树是一个10叉树。

Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。

它的优点是:最大限度地减少无所谓的字符串比较。
它的缺点是:消耗内存大。
在这里插入图片描述

前缀树的3个基本性质:

1.根节点不包含字符,除根节点外每一个节点都只包含一个字符。
2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
3.每个节点的所有子节点包含的字符都不相同。

例题

例题一:统计难题

Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).

Input
输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.

注意:本题只有一组测试数据,处理到文件结束.

Output
对于每个提问,给出以该字符串为前缀的单词的数量.

Sample Input
banana
band
bee
absolute
acm

ba
b
band
abc

Sample Output
2
3
1
0

AC代码:

#include <iostream>
#include <cstdio>
#include <string>
using namespace std;

const int maxn = 5e5 + 10;
int trie[maxn][26];
int tot = 1;
bool mark[maxn];
int num[maxn] = { 0 };

void insert(string a)
{
    int root = 0;
    for (int i = 0; i < a.length(); i++)
    {
        int id = a[i] - 'a';
        if (!trie[root][id])
            trie[root][id] = tot++;
        root = trie[root][id];
        num[root]++;
    }
}

int search(string a)
{
    int root = 0;
    for (int i = 0; i < a.length(); i++)
    {
        int id = a[i] - 'a';
        if (!trie[root][id])
            return false;
        root = trie[root][id];
    }
    return num[root];
}

int main()
{
    string a;
    while (getline(cin, a))
    {
        if (a.length() == 0) break;
        insert(a);
    }
    while (cin >> a)
    {
        cout << search(a) << endl;
    }

	return 0;
}

例题二:Phone List

Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another. Let’s say the phone catalogue listed these numbers:

  1. Emergency 911
  2. Alice 97 625 999
  3. Bob 91 12 54 26
    In this case, it’s not possible to call Bob, because the central would direct your call to the emergency line as soon as you had dialled the first three digits of Bob’s phone number. So this list would not be consistent.

Input
The first line of input gives a single integer, 1 <= t <= 40, the number of test cases. Each test case starts with n, the number of phone numbers, on a separate line, 1 <= n <= 10000. Then follows n lines with one unique phone number on each line. A phone number is a sequence of at most ten digits.

Output
For each test case, output “YES” if the list is consistent, or “NO” otherwise.

Sample Input
2
3
911
97625999
91125426
5
113
12340
123440
12345
98346

Sample Output
NO
YES

AC代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;

const int maxn = 5e5 + 10;
int trie[maxn][10];
int tot = 1;
bool mark[maxn];
bool flag = true;

void insert(string a)
{
    int root = 0;
    for (int i = 0; i < a.length(); i++)
    {
        int id = a[i] - '0';
        if (!trie[root][id])
            trie[root][id] = tot++;
        root = trie[root][id];
        if (mark[root])  flag = false;
    }
    mark[root] = true;
    for (int i = 0; i < 10; i++)
    {
        if (trie[root][i])
            flag = false;
    }
}

void init()
{
    tot = 1;
    flag = true;
    memset(mark, 0, sizeof mark);
    memset(trie, 0, sizeof trie);
}

int main()
{
    string a;
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        init();
        cin >> n;
        for (int i = 0; i < n; i++)
        {
            cin >> a;
            insert(a);
        }
        if (flag)    printf("YES\n");
        else
        {
            printf("NO\n");
        }
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值