ACWing - Trie字符串统计

199 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述:

维护一个字符串集合,支持两种操作:

  1. I x 向集合中插入一个字符串 xx;
  2. Q x 询问一个字符串在集合中出现了多少次。

共有 NN 个操作,输入的字符串总长度不超过 105105,字符串仅包含小写英文字母。

输入格式

第一行包含整数 NN,表示操作数。

接下来 NN 行,每行包含一个操作指令,指令为 I xQ x 中的一种。

输出格式

对于每个询问指令 Q x,都要输出一个整数作为结果,表示 xx 在集合中出现的次数。

每个结果占一行。

数据范围

1≤N≤2∗1041≤N≤2∗104

输入样例:

5
I abc
Q abc
Q ab
I ab
Q ab

输出样例:

1
0
1

二、思路分析:

Trie树是一个高效查找和储存字符串的数据结构

三、AC 代码:

import java.util.Scanner;

public class Main {

    /** 用来存放Trie树 */
    static int[][] son = null;
    /** 以当前这个点结尾的单词有多少个 */
    static int[] cnt;
    /** 存放当前用到的下标 下标是0的节点即是空节点又是根节点*/
    static int idx;

    static void insert(char[] str){
        // 从根节点开始
        int p = 0;
        for (int i = 0; i < str.length; i++) {
            /** u 为子节点编号 */
            int u = str[i] - 'a'; 
            /** 如果不存在该子节点,则创建该子节点 */
            if (son[p][u] == 0) {
                son[p][u] = ++ idx;
            }
            /** p为走到最后的点 */
            p = son[p][u];
        }
        /** 表示以p这个点结尾的单词数量加一 */
        cnt[p]++;
    }
    static int query(char[] str){
        // 从根节点开始
        int p = 0;
        for (int i = 0; i < str.length; i++) {
            int u = str[i] - 'a';
            if(son[p][u] == 0)return 0;
            p = son[p][u];
        }
        // 返回以p为结尾的单词数量
        return cnt[p];
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        in.nextLine();
        son = new int[100010][26]; cnt = new int[100010];
        for (int i = 0; i < n; i++) {
            String[] s = in.nextLine().split(" ");
            if (s[0].equals("I")) {
                insert(s[1].toCharArray());
            }else{
                int result = query(s[1].toCharArray());
                System.out.println(result);
            }
        }
    }
}