数据结构(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; 
} 
复制代码

 

posted @   尊滴菜  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示