字典树

浅谈“踹”字典树

笑着哭i 提交于 2019-12-04 04:08:32
字典树,顾名思义它是棵树,是棵处理字符串的树,具体是棵什么样的树呢,我们可以举个栗子: 假设现在有四个字符串:ych,yk,devot: 那么这棵树大概长这个亚子: 而图中加黑的点,也就是每个单词的终点; 主要用于查询前缀与单词? 然后咱们康实现: 1.插入一个单词: 首先我们设置了一个 \(trie[i][j]\) 数组(这里设trie树中全是小写英文字母,那这样对于每个节点,名义上是有26个子节点的。但是显然我们没必要将空间开的这么大,因为可能在一组数据中,有些字母是没有出现过的,所以我们用多少,开多少),表示以i为根的子树里,第j个字符的编号是多少。 可能有点抽象,我们以上图为例: 假设加入单词的顺序是:ych,yk,devot 那么(设1为根: \[ trie[1][24]=2;\to y\\ trie[2][2]=3;\ \ \to c\\ trie[3][7]=4;\ \ \to h\\ trie[2][10]=5;\to k\\ trie[1][3]=6;\ \ \to d\\ trie[6][4]=7; \ \ \to e\\ trie[7][14]=8;\to o\\ trie[8][19]=9;\to t \] 从这里可以看出,对于一个字母来说,它拥有两个编号,一个编号是固定不变的,也就是我们上面数组中的j,而另一个编号,同一个字母可以不同

poj3630||hdoj1671(字典树)

被刻印的时光 ゝ 提交于 2019-12-04 03:50:09
题目链接:https://vjudge.net/problem/HDU-1671 题意:给定n个字符串,判断是否存在一些字符串是另一些字符串的前缀。 思路:   套模板,存在前缀可能是两种情况:     当前字符串枚举位数时已经存在之前的字符串了;(即已经存在911,当前插入9112)     或者当前字符串枚举完之后,该结点还有子结点。(即已经存在9112,当前插入911) AC code: #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=1e6+5; int T,n,trie[maxn][12],key[maxn],cnt; int flag; char str[12]; void insert(char *s){ int len=strlen(s),u=0; for(int i=0;i<len;++i){ int t=s[i]-'0'; if(!trie[u][t]){ ++cnt; memset(trie[cnt],0,sizeof(trie[cnt])); key[cnt]=0; trie[u][t]=cnt; } if(key[trie[u][t]]){ flag=0; return; } u=trie[u][t]; if(i==len

字典树Trie

拈花ヽ惹草 提交于 2019-12-03 02:51:53
第13次提交终于0->100的原因居然是——没有判重???! https://www.luogu.org/problem/P3879 算是道 略显恶心的 板子题吧,唯一一点以后可以继承的经验是trie数组利用了结构体+vector的方式解决了空间与维度的问题。 1 #include<iostream> 2 #include<cstdio> 3 #include<vector> 4 #include<cstring> 5 using namespace std; 6 7 struct Node{ 8 int a[26]; 9 Node(){memset(a,0,sizeof a);} 10 int& operator [](int x){return a[x];} 11 }zero; 12 13 string s; 14 vector<Node> trie; 15 vector<int> cntw[500010]; 16 17 void add(int i){ 18 int p = 0; 19 for(int j = 0;j < s.size();j++){ 20 int ne = s[j]-'a'; 21 if(!trie[p][ne]){ 22 trie[p][ne] = trie.size(); 23 trie.push_back(zero); 24 } 25 p = trie

[BZOJ4260] Codechef REBXOR (01字典树,异或前缀和)

匿名 (未验证) 提交于 2019-12-03 00:39:02
Description Input 输入数据的第一行包含一个整数N,表示数组中的元素个数。 第二行包含N个整数A1,A2,…,AN。 Output 输出一行包含给定表达式可能的最大值。 Sample Input 5 1 2 3 1 2 Sample Output 6 HINT 满足条件的(l1,r1,l2,r2)有:(1,2,3,3),(1,2,4,5),(3,3,4,5)。 对于100%的数据,2 ≤ N ≤ 4*105,0 ≤ Ai ≤ 109。 Source By yts1999 Solution 这道题,似乎也是套路题啊,只不过多了那么一点点思路。 考虑几点: 我们所选的区间不能相交。 显而易见的贪心,我们所选的区间必须是区域内异或和最大的。 于是我们考虑用 01字典树 来求解。 我们可以很方便地处理出在一段区间内最大异或和的区间。 直接记录一遍异或前缀和,然后一个一个插入并查询即可。 但是由于不能选相交的区间,我们不能考虑直接选两个最大的区间。 可以考虑用一个数组: \[f[maxn]\] 用于储存前 ( 1 , i ) 区间的异或最大值。 那么我们记录完之后,直接从后面再开始一遍选最大区间。 我们从 n枚举到 1; \[Ans=\max_{i=1}^n(Ans,f[i-1]+query(sub[i]))\] 其中sub 数组表示 n 到 i 异或后缀和。 如以上求解即可

【HDU 2072 单词数】 字典树/SET

匿名 (未验证) 提交于 2019-12-03 00:26:01
HDU2072 题意就是出现的不同单词个数 直接把字符全部插入Trie树中,然后统计所有具有flagg标记的节点个数就好了。 也可以边插入边统计,如果当前字符串结尾下标已经被标记,就不对答案做贡献,否则ans++. HDU 2072 代码 #include <stdio.h> #include <iostream> #include <string.h> #include <sstream> using namespace std ; const int maxn = 2e6 + 5 ; int tree [ maxn ][ 30 ]; bool flagg [ maxn ]; int tot ; void insert_ ( string str ) { int len = str . size (); int root = 0 ; for ( int i = 0 ; i < len ; i ++) { int id = str [ i ]- 'a' ; if (! tree [ root ][ id ]) tree [ root ][ id ]=++ tot ; root = tree [ root ][ id ]; } flagg [ root ]= true ; } bool find_ ( string str ) { int len = str . size ();

【HDU 1247 Hat’s Words】字典树(Trie树)

匿名 (未验证) 提交于 2019-12-03 00:26:01
HDU1247 本题题意是问你某个单词是否可以拆成单词表中的其他两个单词。 我们可以建两颗Trie树,然后分别正序倒序插入每个单词,对每个单词查询的时候,我们分别正序倒序查询,对出现过单词的前缀下表进行标记,对每个出现过单词的后缀进行标记,最后扫描标记数组,如果某个位置前缀后缀均被标记过,则表示可以拆成单词表中的两个其他单词。 HDU1247代码 #include <stdio.h> #include <iostream> #include <string.h> #include <sstream> #include <set> using namespace std ; const int maxn = 2e6 + 5 ; int tree [ maxn ][ 30 ], tree2 [ maxn ][ 30 ]; set < string > s ; bool flagg [ maxn ], flagg2 [ maxn ]; int sum [ 55 ]; int tot , tot2 ; void insert_ ( char * str ) { int len = strlen ( str ); int root = 0 ; for ( int i = 0 ; i < len ; i ++) { int id = str [ i ]- 'a' ; if (! tree [

【POJ 2408 Anagram Groups】 字典树(Trie树)

匿名 (未验证) 提交于 2019-12-03 00:26:01
POJ2408 本题题意是,把可以通过重新排列变成相同单词的单词放入一个集合,最后按找集合元素由多到少输出前五个集合,如果几何元素相同,按照字典序由小到大输出 我们考虑,如果两个单词可以通过重新排列组合变成相同单词,那么他们的字典序最小的排列方式一定是相同的,所以我们可以利用每个元素的最小排列方式判定是否在同一个集合,字典树在这里用于判定某个字符串时候出现过。最后用set来保存以便维持字典序 POJ2408代码 #include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> #include <set> #include <vector> using namespace std ; const int maxn = 1e6 + 5 ; int tree [ maxn ][ 30 ]; char ss [ maxn ]; int tot , anstot ; int num [ 30 ]; int vis [ maxn ]; struct data { int num ; set < string > s ; } cnt [ maxn ]; bool cmp ( const data & a , const data & b ) { if ( a . num == b . num ) {

字典树遍历实现字符串敏感词替换

匿名 (未验证) 提交于 2019-12-03 00:21:02
何为字典树? 字典树(Trie树),又称前缀树,一种Hash树的变种,用于统计,排序和保存大量的 字符串,利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较 利用字典树对大段文字进行搜索,查找敏感词并进行打码替换 将敏感词词库以字符的形式保存到字典树中,例如敏感词词库中包含了“色情”、“赌博”、“暴力”,则需要生成这么一棵树: 其中根节点不对应任何字符,尾部节点进行标记,表示这是一个词的结尾。 删选敏感词时,对大段文字进行遍历,同时在字典树中进行查找匹配,找到文字中的敏感词并将敏感词替换为“***”符号,以下是详细代码 构造字典树 构造方案是构建一个Node类来表示各节点,Node的成员变量是一个保存有各子节点的Map,key为单个字符,value为子节点Node: //字典树节点,其中包含一个Map,该Map保存了所有子节点,key为节点对应的字符 private class TrieNode{ private boolean end = false; private Map<Character, TrieNode> subNodes = new HashMap<>(); private void addSubNode(Character key, TrieNode node){ subNodes.put(key, node); } private

数据结构与算法,应对程序员面试,你必须知道的八大数据结构

匿名 (未验证) 提交于 2019-12-03 00:05:01
什么是数据结构? 简单地说,数据结构是以某种特定的布局方式存储数据的容器。这种“布局方式”决定了数据结构对于某些操作是高效的,而对于其他操作则是低效的。首先我们需要理解各种数据结构,才能在处理实际问题时选取最合适的数据结构。 为什么我们需要数据结构? 数据是计算机科学当中最关键的实体,而数据结构则可以将数据以某种组织形式存储,因此,数据结构的价值不言而喻。 无论你以何种方式解决何种问题,你都需要处理数据――无论是涉及员工薪水、股票价格、购物清单,还是只是简单的电话簿问题。 数据需要根据不同的场景,按照特定的格式进行存储。有很多数据结构能够满足以不同格式存储数据的需求。 常见的数据结构 首先列出一些最常见的数据结构,我们将逐一说明: 数组 ջ 队列 链表 树 ͼ 字典树(这是一种高效的树形结构,但值得单独说明) 散列表(哈希表) 数组 数组是最简单、也是使用最广泛的数据结构。栈、队列等其他数据结构均由数组演变而来。下图是一个包含元素(1,2,3和4)的简单数组,数组长度为4。 每个数据元素都关联一个正数值,我们称之为索引,它表明数组中每个元素所在的位置。大部分语言将初始索引定义为零。 以下是数组的两种类型: 一维数组(如上所示) 多维数组(数组的数组) 数组的基本操作 Insert――在指定索引位置插入一个元素 Get――返回指定索引位置的元素 Delete――删除指定索引位置的元素

「字典树」[TJOI2010]阅读理解

匿名 (未验证) 提交于 2019-12-03 00:03:02
原题链接: [TJOJ2010]阅读理解 给你很多个字符串,再给你单个字符串,问后面单个字符串是否在前面多个字符串中出现过 很简单..不用我多说 2 3分钟写完 但是!我交了20多遍,为什么? TM它卡bool(草 这道题让我理解了什么叫 \(bitset\) ,以后就不用bool了 quq //#define fre yes #include <bitset> #include <cstdio> #include <cstring> const int N = 600010; struct Node { int son[26]; } trie[N]; std::bitset<1001> b[500007]; int tnt; void trieInsert(char c[], int k) { int len = strlen(c + 1); int rt = 0; for (int i = 1; i <= len; i++) { int id = c[i] - 'a'; if(!trie[rt].son[id]) trie[rt].son[id] = ++tnt; rt = trie[rt].son[id]; } b[rt][k] = 1; } int n; void trieFind(char c[]) { int len = strlen(c + 1); int flag