字典树 : 见名知意(在树上进行查询)。 跟字典相关的一定与查询有密切的关系, 查询就须要必定的媒介做为支撑,树就为这种查询提供支撑。
实现字符串快速检索的多叉树结构。 常见的字符串转化:小写字母或者大写字母组成的字符串,数字组成的字符串,01编码组成的字符串。
Trie 的每一个节点都拥有若干个字符指针,就是说每一个节点有多个子节点,通俗一点就是至关于古代 的大少爷能够有多个妻子。
一、插入(将一个字符串插入到字典树上) 二、检索(检索一个字符串 S 在Trie 上是否存在)
假设有单词 : cab , cef , da 这样三个单词,那么这样三个单词组成的图是什么样的呢 ? 看下图 : (一般还要在末尾进行标记一下,表示到字符串的末尾)
插入 : 像每一个单词拼写同样,单词的开头就至关因而咱们的根,从根节点出发,向儿子节点前进。 在向下走的过程当中,看有没有当前这个字符的节点,若是有这个节点,就顺着这个节点继续 往下走,若是没有这个节点,就在这个节点之下再建立一个节点。 拿一个例子来讲: 好比上图的 cab 和 cef, 先插入第一个字符串,从根节点出发,第一个字符是 c,咱们发 现没有这个字符的节点,因此建立一个节点,将指针节点进行指向,而后一直向下移动,知道 字符串结尾。再插入第二个字符串,先检测第一个字符是否存在,咱们发现存在,因此不用 建立,直接向下移动指针节点便可。 能够发现: 一个节点最多能够有26个孩子。 检索: 只须要将字符串遍历一遍,顺着根节点下来看这条路径上是否有不存在的值,即 0,若是 没有到末尾就发现有 0 ,说明这个字符串不存在,反之即存在。
插入:ios
void insert(char str[]) { int len = strlen(str),p = 0; // p 做为根节点从 0 开始 for(int i = 0; i < len; i ++) { int ch = str[i] - 'a'; if(trie[p][ch] == 0) trie[p][ch] = ++ idx; // 建立新的节点 p = trie[p][ch]; // 指针移动 } End[p] = true; // 在末尾进行标记 return ; }
检索:数组
bool query(char str[]) { int len = strlen(str),p = 0; for(int i = 0; i < len; i ++ ){ int ch = str[i] - '0'; if(trie[p][ch] != 0) { p = trie[p][ch]; } else { break; // 及时跳出 } } return true; }
题目连接: https://www.acwing.com/problem/content/144/ 题目描述:给定N个字符串S1,S2…SN,接下来进行M次询问,每次询问给定一个字符串T,求S1~SN中有多少个字符串是T的前缀。 输入字符串的总长度不超过106,仅包含小写字母。 输入格式 第一行输入两个整数N,M。 接下来N行每行输入一个字符串Si。 接下来M行每行一个字符串T用以询问。 输出格式 对于每一个询问,输出一个整数表示答案。 每一个答案占一行。 输入样例: 3 2 ab bc abc abc efg 输出样例: 2 0
析题得说: 统计每一个字符串出现的个数便可,用一个cnt[]数组记录每一个字符串出现的个数,而后进行检索要处理的字符串,累加结果(模板题)编码
#include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int SIZE = 1e6 + 10; int trie[SIZE][26],cnt[SIZE]; char str[SIZE]; int n,m,idx = 0; int main(void) { void insert(); int query(); scanf("%d%d",&n,&m); for(int i = 1; i <= n; i ++) { scanf("%s",str); insert(); } while(m --) { scanf("%s",str); printf("%d\n",query()); } return 0; } void insert() { int p = 0; for(int i = 0; i < strlen(str); i ++) { int ch = str[i] - 'a'; if(trie[p][ch] == 0) trie[p][ch] = ++ idx; p = trie[p][ch]; } cnt[p] ++; // 统计该字符串的个数 return ; } int query() { int p = 0,res = 0; for(int i = 0 ; i < strlen(str); i ++) { int ch = str[i] - 'a'; if(trie[p][ch] != 0) { p = trie[p][ch]; res += cnt[p]; // 将以该字符结尾的数量累加,最后结果就是前缀字符串的数量 } else { break; } } return res; }