算法学习之Trie树
by MPS
【定义】
  trie树又名字母树,是针对字符串的匹配,查找的一种高效手段,是哈希表的一种变种,但青出于蓝胜于蓝。我这个蒟蒻也是表示啃了两天才啃出来这些皮毛,当做学习笔记,关于trie树的外貌,大概如下:
                                                            
显然,这棵树有三个特点:
(1)有一个完全没有用的根(在生物上好像叫假根来着....)
(2)每个节点都是由一个字符构成
(3)路径连起来就是一个字符串
另外,图中有一些红节点,这是为了以后查询是否存在而做的铺垫
【trie树的深入】
  trie的好处在于无需构造,为什么这样说呢?因为我们发现,事实上,构造就是插入,插入就是“沿着前人的光荣传统,没有就自己开垦。”然后查找就更不用说了,具体统计出现频率只需要增加数据域即可
【trie树的模板】
(以@NOIRP同学出的一道题目为例子,方便引入模板)
                                                                           《英语时态》
     #题目描述#
        对于给定的一个单词,可能会有n种时态,对于不同的时态,小J同学就有点晕了,于是决定把它们分类,也就是对于每一个单词,它应该属于第几个柜子?对于能放在一个柜子的条件是当且仅当这几个单词一样。举个例子:
        3
        become
        became
        become
        那么很显然,become放在第一个柜子,became放在第二个柜子,这时,出现了重复的单词become,所以也放在第一个柜子,那么输出应该是
        1 2 1
     (注意,类似于:
          become
          become
          became
         则became应装进第三个柜子
       )
   #输入描述#
        第一行n
        第二行至第n+1行,每行一个单词(只包含小写字母和数字0-9)
  #输出描述#
         如题
  #数据范围#
       对于20%的数据,n≤1000,单词长度≤8
       对于100%的数据,n≤30001,单词长度≤20
【分析】
  题目的意思很明显,对于一个单词,查找之前是否出现过,如果出现过则输出第一次出现的序号,否则输出当前的序号,这时,思路涌现:
  (1)O(N^2)暴力,不过很明显TLE
  (2)哈希表优化,由于单词是只包含小写字母和数字0-9,所以弄一个哈希表记录下来,时间复杂度O(N),不过我们仔细观察:假设我们将一个字母都转为数字以后累加(这样才能不冲突),那么当单词长度为20,且每一个字母都是a,那么空间需求要60^20,太恐怖了,承受不起,所以MLE,可以用拉链法优化
(3)我们想到了学习主题——trie树,只要打一个id域即可!
       (补充:trie树查询插入删除的复杂度都是O(单词长度))
        那么时间复杂度就应该是O(N*L^2),正好卡时间AC!
【代码】
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cctype>
#include <cstring>
#include <string>
#include <cstdlib>
#include <vector>
#include <queue>
#include <deque>
using namespace std;const int MaxL=20;
const int MAXS=100;
const int MaxN=30001;typedef struct Trie_tree{int id;struct Trie_tree *next[MAXS];
}TrieNode,*Trie;TrieNode* creat(){TrieNode* root=(TrieNode *)malloc(sizeof(TrieNode));root->id=0;memset(root->next,0,sizeof(root->next));return root;
}
int i;
Trie t;int change(char x){if(x>='a' && x<='z')return x-'a';else return x-'0';
}int Search(Trie root,char* word){TrieNode* node=root;char* p=word;while(*p && node!=NULL){node=node->next[(change(*p))];p++;}if(node!=NULL && node->id!=0)return node->id;elsereturn i;
}void Insert(Trie root,char* word){TrieNode* node=root;char* p=word;while(*p){if(node->next[change(*p)]==NULL)node->next[change(*p)]=creat();node=node->next[change(*p)];p++;}node->id=Search(t,word);
}int Count(Trie root,char* word){TrieNode* node=root;char* p=word;while(*p && node!=NULL){node=node->next[change(*p)];p++;}return node->id;
}int n;
char word[MaxN][MaxL];
int main(){freopen("letter.in","r",stdin);freopen("letter.out","w",stdout);scanf("%d",&n);t=creat();for(i=1;i<=n;i++){scanf("%s",word[i]);Insert(t,word[i]);}for(i=1;i<=n;i++)printf("%d ",Count(t,word[i]));return 0;
}
例题2:《Contact 联系》(来源:USACO)

Contact

联系
IOI'98

译 by Henry HuGang HuGangMail

奶牛们开始对用电波望远镜扫描牧场外的宇宙感兴趣。最近,他们注意到了一种非常奇怪的脉冲调制微波被从星系的中央发射出来。他们希望知道电波是否是被某些地外生命发射出来的,还是仅仅是普通的的星星的心跳。

帮助奶牛们用一个能够分析他们在文件中记下的记录的工具来找到真相。他们在寻找长度在A到B之间(含)在每天的数据文件中重复得最多的比特序列 (1 <= A <= B <= 12)。他们在找那些重复得最多的比特序列。一个输入限制告诉你应输出多少频率最多的序列。

符合的序列可能会重叠,并且至少重复一次的序列会被计数。

PROGRAM NAME: contact

INPUT FORMAT

第一行:

三个用空格分隔的整数: A, B, N; (1 <= N < 50)

第二行及以后:

一个最多2000字符的序列,全是0或1; 每行有80个字符,除了可能的最后一行。

SAMPLE INPUT (file contact.in)

2 4 10 01010010010001000111101100001010011001111000010010011110010000000

在样例里,序列100出现了12次,而序列1000出现了5次。次数最多的序列是00,出现了23次。

OUTPUT FORMAT

输出N个频率最高的序列(按照频率由高到低的次序)。由短到长排列频率相同的这些序列,如果长短相同,按二进制大小排列。如果出现的序列个数小于N,输出存在的序列。

对于每个存在的频率,先输出单独包含该频率的一行,再输出以空格分隔的这些频率。每行六个(除非少于六个剩下)。

SAMPLE OUTPUT (file contact.out)

23001501 10121001111 000 001100108010070010 10016111 00005011 110 100040001 0011 1100

【分析】
  不难发现,这题的主要思想还是查询是否出现,当然这题也可以暴力,只不过会TLE的很惨。。。
  万变不离其宗——trie树
  打个cnt域即可
【代码】
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cctype>
#include <cstring>
#include <string>
#include <cstdlib>
#include <vector>
#include <queue>
#include <deque>
using namespace std;const int MaxN=101;
const int MaxSize=2;
const int MaxM=10001;typedef struct Trie_tree{int cnt;struct Trie_tree* next[MaxSize];//对于每一个数组只有0或者1两个孩子
}TrieNode,*Trie;TrieNode* creat(){TrieNode* root=(TrieNode*)malloc(sizeof(TrieNode));root->cnt=0;memset(root->next,0,sizeof(root->next));return root;
}int comp(char A[],char B[]){int l1=strlen(A),l2=strlen(B);if(l1<l2)return 1;if(l1>l2)return -1;for(int i=0;i<l1;i++)if(A[i]<B[i])return 1;else if(B[i]<A[i])return -1;return 0;
}struct result{char s[MaxN];int c;friend bool operator< (result a,result b){if(a.c!=b.c)return a.c>b.c;//次数从大到小排序 elsereturn comp(a.s,b.s); }
}ans[MaxM],res[51];char str[MaxN];
int a,b,n,len;
int total;//答案个数 void readfile(){scanf("%d%d%d",&a,&b,&n);char c;scanf("\n");while(~scanf("%c",&c))if(c!='\n')str[len++]=c;
}void Insert(Trie root,char* word){TrieNode* node=root;char *p=word;while(*p){if(node->next[*p-'0']==NULL)node->next[*p-'0']=creat();node=node->next[*p-'0'];p++;}node->cnt++;
}int Count(Trie root,char* word){TrieNode* node=root;char* p=word;while(*p && node!=NULL){node=node->next[*p-'0'];p++;}return node->cnt;
}char word[MaxN];
void trie_tree(){int i,j,k;Trie t=creat();for(i=0;i<=len-a;i++){memset(word,'\0',sizeof(word));for(j=a;j<=b;j++){if(i+j-1>=len)continue;for(k=i;k<=i+j-1;k++)word[k-i]=str[k];Insert(t,word);}}for(i=0;i<=len-a;i++){memset(word,'\0',sizeof(word));for(j=a;j<=b;j++){if(i+j-1>=len)continue;for(k=i;k<=i+j-1;k++){word[k-i]=str[k];ans[total].s[k-i]=str[k];}ans[total].c=Count(t,word);total++;}}
}void out(){//最后输出的部分有些凌乱,读者可以自行修改int i,j,last=0,tmp=1,calc=0,ac=0;sort(ans,ans+total);for(i=0;i<total;i++){if(ans[i].c!=last){calc++;last=ans[i].c;if(calc>n)break;}if(i==0 || strcmp(ans[i].s,ans[i-1].s)!=0)res[ac++]=ans[i];}last=-1;calc=0;sort(res,res+ac);for(i=0;i<ac;i++){if(tmp%6==0)printf("\n");if(res[i].c!=last){if(i!=0)printf("\n");calc++;if(calc>n)break;printf("%d\n",res[i].c);last=res[i].c;tmp=0;}printf("%s ",res[i].s);tmp++;}
}int main(){freopen("contact.in","r",stdin);freopen("contact.out","w",stdout);readfile();trie_tree();out();return 0;
}

算法学习之Trie树相关推荐

  1. 【算法学习】前缀树Trie

    Tire(前缀树) 一.定义: Trie(发音类似 "try")或者说前缀树是一种树形数据结构,用于高效地存储和检索字符串数据集中的键. 其核心是使用「边」来代表有无字符,使用「点 ...

  2. 数据结构与算法 / 字符串匹配 / Trie 树

    一.诞生原因 传统字符串比较时,需要将待比较的字符串与字符串集合中每一个串进行比较,结果比较浪费时间. Trie 树的发明就是为了解决上述问题. 二.基本信息 又称字典树,是一种树形结构,是一种哈希树 ...

  3. 算法学习:主席树(可持久化线段树)

    [前置知识]  线段树 [定义] [可持久化]能够保存历史版本,方便操作区间等,减少复杂度 [主席树] 可解决的经典问题区间第k大/小 时空复杂度为O(nlogn) [模板题] [luogu 3834 ...

  4. 【算法学习4】树与二叉树基础

    首先是部分树方面的概念 节点:节点包括一个数据元素及若干指向其他子树的分支. 叶节点:度为0的节点称为叶结点,叶结点也称为终端节点. 根节点:树的最顶端的节点称为根节点. 子节点:树中一个节点的子树的 ...

  5. 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)

    图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...

  6. 字符串匹配算法 -- AC自动机 基于Trie树的高效的敏感词过滤算法

    文章目录 1. 算法背景 2. AC自动机实现原理 2.1 构建失败指针 2.2 依赖失败指针过滤敏感词 3. 复杂度及完整代码 1. 算法背景 之前介绍过单模式串匹配的高效算法:BM和KMP 以及 ...

  7. 字符串匹配数据结构 --Trie树 高效实现搜索词提示 / IDE自动补全

    文章目录 1. 算法背景 2. Trie 树实现原理 2.1 Trie 树的构建 2.2 Trie树的查找 2.3 Trie树的遍历 2.4 Trie树的时间/空间复杂度 2.5 Trie 树 Vs ...

  8. 算法 | 动画+解析,轻松理解「Trie树」

    Trie这个名字取自"retrieval",检索,因为Trie可以只用一个前缀便可以在一部字典中找到想要的单词. 虽然发音与「Tree」一致,但为了将这种 字典树 与 普通二叉树 ...

  9. mysql索引用trie树_数据结构与算法之美【完整版】

    资源目录: ├─01-开篇词 (1讲) │ ├─00丨开篇词丨从今天起,跨过"数据结构与算法"这道坎.html │ ├─00丨开篇词丨从今天起,跨过"数据结构与算法&qu ...

最新文章

  1. [置顶] PHP如何扩展和如何在linux底层对php扩展?
  2. python中包的循环导入_具有继承的包中的循环导入依赖项
  3. openmv串口数据 串口助手_STM32 串口接收不定长数据 STM32 USART空闲检测中断
  4. 【转】搞机:window10安装Linux子系统(WSL)及迁移到非系统盘
  5. DB2临时表空间的作用
  6. python 蒙特卡罗_蒙特卡洛模拟(Python)深入教程
  7. AOJ0028 Mode Value【出现次数最多+map+vector+水题】
  8. 基于Python的Landsat影像建设用地自动识别与提取
  9. 【BZOJ5100】[POI2018]Plan metra 构造
  10. Tableau宣布退出中国市场,背后的原因细思恐极...
  11. 【深入理解Java原理】Java类加载机制
  12. 电脑分屏没有声音_电脑用HDMI线分屏后,耳机或音箱没声音之完美解决!
  13. pdf照片显示正常打印时被翻转_要哭了,差点打印不了准考证!(2021考生提前收藏!)...
  14. 学计算机的一直对画画感兴趣,[电脑绘画兴趣小组教学总结]sai电脑绘画入门教学...
  15. python使用UDP协议进行远程桌面共享
  16. 给ecmall添加积分购物的功能
  17. 使用 Python 和 Bitly 缩短您的 URL
  18. 今天距离2022年除夕还有多少天?春节放假倒计时在手机便签上提醒
  19. 视频突破500播放量的神操作秘密
  20. css去掉ie浏览器输入框后面的小叉叉,和密码框后面的小眼睛

热门文章

  1. 2022年修复版周易起名网站源码+PHP内核
  2. anki计算机知识,「背书 刷题神器」 Anki 是应对考试的强力效率 buff
  3. Jenkins 添加Allure报告 并发送企业微信通知
  4. HTML 图片鼠标悬停动态效果
  5. python爬取证券数据并存入数据库
  6. Python:max函数获取列表最大值
  7. CSDN取消手机绑定
  8. git restore指令和git restore --staged 的使用
  9. Python求解多个多元一次方程组(完整可运行版本代码)
  10. Google Pay支付遇到的问题,妈妈再也不用担心我的面试