数据结构(2)
trie树
主要作用:快速存储、查找字符串
单词的结尾要进行标记,表示“到达该节点,存在一个单词”
#include <iostream> using namespace std; const int N = 1e6+10; int son[N][26] ; //字母最多26个 int cnt[N], idx ; //下标为0的点,是根节点,也是空结点 void insert(char str[ ]) { int p = 0 ; // 从根节点开始 for( int i=0; str[i] ; i++ ) { int u = str[i] -'a' ; //当前字母的结点编号 if( !son[p][u] ) son[p][u] = ++ idx ; //当前结点不存在这个字母,则创建 p = son[p][u] ; // 子节点作为新的根继续往下查 } cnt[p] ++ ; } int query( char str[]){ int p = 0 ; for( int i=0; str[i]; i++ ) { int u = str[i]-'a'; if(!son[p][u]) return 0; //不存在这个点 p = son[p][u]; } return cnt[p]; //存在,返回这个点的出现次数 } int main(){ int m ; cin>>m ; while(m--){ char op, str[N]; cin>>op>>str ; if( op=='I') insert(str) ; else printf("%d\n", query(str)) ; }
return 0; }
题目:最大异或数
在给定的 <span id="MathJax-Span-2" class="mrow"><span id="MathJax-Span-3" class="mi">N个整数 <span id="MathJax-Span-5" class="mrow"><span id="MathJax-Span-6" class="msubsup"><span id="MathJax-Span-7" class="mi">A<span id="MathJax-Span-8" class="mn">1<span id="MathJax-Span-9" class="texatom"><span id="MathJax-Span-10" class="mrow"><span id="MathJax-Span-11" class="mo">,<span id="MathJax-Span-12" class="msubsup"><span id="MathJax-Span-13" class="mi">A<span id="MathJax-Span-14" class="mn">2<span id="MathJax-Span-15" class="mo">…<span id="MathJax-Span-16" class="mo">…<span id="MathJax-Span-17" class="msubsup"><span id="MathJax-Span-18" class="mi">A<span id="MathJax-Span-19" class="mi">N中选出两个进行 <span id="MathJax-Span-21" class="mrow"><span id="MathJax-Span-22" class="mi">x<span id="MathJax-Span-23" class="mi">o<span id="MathJax-Span-24" class="mi">r(异或)运算,得到的结果最大是多少?
1->001 1 xor 2 = 011 1 xor 3 = 010
2->010
3->011
利用trie树,边插入边查找,每个二进制数查找它对应的异或最大数只需要尽力去走插入这个数相反的路
#include <iostream> #include <algorithm> using namespace std; const int N = 1e6+10; int son[N*31][2] ; //防止超出范围 int a[N], idx ; void insert(int x) { int p = 0 ; // 从根节点开始 for( int i=30; i>=0; i-- ) { int u = x >> i & 1 ; //看个位是什么 if( !son[p][u] ) son[p][u] = ++idx; p = son[p][u]; } } int query(int x){ int p = 0, res = 0 ; for(int i=30; i>=0; i--) { int u = x >> i & 1; if( son[p][!u] ){ p = son[p][u] ; //找得到相反路就走 res = res*2 + !u ; } else{ p = son[p][u]; res = res*2 + u ; } } return res ; } void query(){ } int main(){ int m ; cin>>m ; for(int i=0; i<m; i++ ) scanf("%d", &a[i]) ; int res = 0 ; for(int i=0; i<m; i++) { insert(a[i]) ; int t = query(a[i]) ; res = max(res, a[i]^t) ; // ^ 表示异或 } printf("%d\n", res) ; return 0; }
并查集(接近O(1))
查询过一遍后,将叶子节点上直接指向根结点(路径压缩)
#include <iostream> using namespace std ; const int N = 1e6 ; int p[N] ; //父节点 int n,m ; int find(int x){ //返回x的祖宗结点,路径压缩 if( p[x] != x ) p[x] = find(p[x]) ; return p[x] ; } int main(){ cin>>n>>m ; for(int i=1 ; i<=n ; i++ ) p[i] = i ; while(m--) { char op ; int a,b ; cin>>op>>a>>b ; if( op == 'M' ) p[find(a)] = find(b) ; //合并,把b的祖宗结点变成a的祖宗的父节点 else{ if( find(a) == find(b) ) cout<<"Yes\n"; //祖宗相同,同一个集合 else cout<<"No"<<endl; } } return 0; }
PS: 本文来自博客园,作者:尊滴菜,转载请注明原文链接:https://www.cnblogs.com/zundicai/p/17257573.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通