算法二十八:前缀

描述

给定n个字符串,再询问m次,每个询问给出一个字符串,求出这个字符串是n个字符串里,多少个串的前缀。

前缀:从头开始的一段连续子串。比如字符串ab是字符串abcd的前缀,也是字符串ab(自身)的前缀,但不是bab的前缀。

输入

第一行包含两个正整数n,m。

接下来n行,每行表示一个字符串,表示给定的n个字符串中的一个。

再接下来m行,每行一个字符串,表示询问的字符串。

输出

输出m行,每行表示询问的答案。

样例输入

5 4
ab
abc
ab
ba
bb
a
b
ab
abc

样例输出

3
2
3
1

样例解释

字符串a是ab、abc、ab的前缀;

字符串b是ba、bb的前缀;

字符串ab是ab、abc、ab的前缀;

字符串abc是abc的前缀。

提示

[trie树基本题。]

一. 伪代码

二. 具体实现(C++)

#include <bits/stdc++.h>
using namespace std;
// ================= 代码实现开始 =================
const int M = 505, L = 1000005;
// c:trie树上的边,c[x][y]表示从节点x出发(x从1开始),字符为y的边(y范围是0到25)
// sz:sz[x]表示x节点的子树中终止节点的数量(子树包括x自身)
// cnt:trie树上节点的数目
int c[L][26], sz[L], cnt;
// 将字符串s加入到trie树中
// s:所要插入的字符串

void add(char *s) {
    int x =0;
    for(;*s;++s){
        int y = *s -'a';
        if(!c[x][y])
            c[x][y] = ++cnt;
        x=c[x][y];
    }
     ++sz[x];
}
// 用于计算sz数组
// x:当前节点

void dfs(int x) {
    for(int y=0; y<26; ++y){
        int z = c[x][y];
        if(z!=0){
            dfs(z);
            sz[x] += sz[z];
        }
    }
}
// 用字符串s沿着trie树上走,找到相应的节点
// s:所给字符串
// 返回值:走到的节点

int walk(char *s) {
   int x = 0;
   for(; *s; ++s){
        int y = *s - 'a';
        if(!c[x][y])
            return 0;
        x = c[x][y];
   }
   return x;
}
// ================= 代码实现结束 =================


猜你喜欢

转载自blog.csdn.net/wydyd110/article/details/80909510