zoukankan      html  css  js  c++  java
  • 字典树&&01字典树专题&&对字典树的理解

    对于字典树和01字典树的一点理解:

    首先,字典树建树的过程就是按照每个数的前缀来的,如果你要存储一个全小写字母字符串,那么这个树每一个节点最多26个节点,这样的话,如果要找特定的单词的话,按照建树的方式找就可以了。

    然后是01字典树,这个树在处理一些异或问题的时候特别好用,首先在存储一个树的过程中,我们是按照从高位开始的,如果是对于int型的,我们就从这个数的32位开始存储,不够的话,按照0补,这是建树的过程。再就是查询的时候,对于给定的数,我们先去找这一位上和他不同的,比如说,如果当前这个数的第i位上是1,那我们就找有没有一个数第i位上是0,如果没有的话,再去找第i位是0的数,然后按照从高位到低位寻找的话,就一定能寻找到满足情况的最优解。

    入门:

    题目链接:http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Index/problemdetail/pid/2828.html

    用数组模拟。

    我的理解:假设给你n个字符串,我们可以把有相同前缀的按照树的形式存储下来,这样就能够节省很多的空间,然后通过递归的形式来建树或者查找子串是否存在或者存在的次数。

    AC代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 1e6+10;
     4 char tmp[maxn];
     5 int root[maxn][30];
     6 int top;
     7 void init()
     8 {
     9     for(int i=0; i<top; i++)
    10     {
    11         for(int j=0; j<30; j++)
    12         {
    13             root[i][j]=0;
    14         }
    15     }
    16     top=0;
    17 }
    18 void add(char *str)
    19 {
    20     int tot=0;
    21     int len=strlen(str);
    22     for(int i=0; i<len; i++)
    23     {
    24         int t=str[i]-'a';
    25         if(root[tot][t]==0)
    26             root[tot][t]=++top;
    27         tot=root[tot][t];
    28     }
    29 }
    30 bool judge(char *str)
    31 {
    32     int len=strlen(str);
    33     int tot=0;
    34     for(int i=0; i<len; i++)
    35     {
    36         int t=str[i]-'a';
    37         if(root[tot][t]==0)
    38             return false;
    39         tot=root[tot][t];
    40     }
    41     return true;
    42 }
    43 int main()
    44 {
    45     int n,m;
    46     top=0;
    47     while(~scanf("%d %d",&n,&m)&&(n+m))
    48     {
    49         init();
    50         for(int i=1; i<=n; i++)
    51         {
    52            // getchar();
    53             scanf("%s",tmp);
    54             add(tmp);
    55            // cout<<tmp<<endl;
    56         }
    57         for(int i=1; i<=m; i++)
    58         {
    59           //  getchar();
    60             scanf("%s",tmp);
    61             if(judge(tmp))
    62                 printf("Yes
    ");
    63             else
    64                 printf("No
    ");
    65         }
    66     }
    67     return 0;
    68 }

    A题:

    题目链接:https://cn.vjudge.net/contest/276901#problem/A

    题目大意:先输入若干个字符串,然后再每一次输入一个字符串,问你当前这个字符串再一开始输入的字符串中是前缀的有多少个?

    AC代码:

     1 #include<iostream>
     2 #include<stack>
     3 #include<string>
     4 #include<cstring>
     5 #include<stdio.h>
     6 using namespace std;
     7 # define ll long long
     8 const int maxn = 2e6+100;
     9 int rec[maxn][30];
    10 int flag[maxn];
    11 int tot;
    12 char str1[maxn];
    13 void add(char *str)
    14 {
    15     int root=0;
    16     int len=strlen(str);
    17     for(int i=0; i<len; i++)
    18     {
    19         int t=str[i]-'a';
    20         if(!rec[root][t])
    21             rec[root][t]=++tot;
    22         flag[rec[root][t]]++;
    23         root=rec[root][t];
    24 
    25     }
    26 }
    27 int judge(char *str)
    28 {
    29     int root=0;
    30     int len=strlen(str);
    31     for(int i=0; i<len; i++)
    32     {
    33         int t=str[i]-'a';
    34         if(rec[root][t]==0)
    35             return 0;
    36         root=rec[root][t];
    37         //cout<<i<<endl;
    38     }
    39     return flag[root];
    40 }
    41 void init()
    42 {
    43     for(int i=0; i<tot; i++)
    44     {
    45         for(int j=0; j<30; j++)
    46         {
    47             rec[i][j]=0;
    48         }
    49     }
    50     tot=0;
    51 }
    52 int main()
    53 {
    54     tot=0;
    55     while(gets(str1))
    56     {
    57         if(str1[0]=='') break;
    58         add(str1);
    59     }
    60     while(scanf("%s",str1)!=EOF)
    61     {
    62         printf("%d
    ",judge(str1));
    63     }
    64     return 0;
    65 }
    66    // init();
    67 //    while(gets(str1))
    68 //    {
    69 //        if(str1[0]=='')
    70 //            break;
    71 //        scanf("%s",str1);
    72 //        add(str1);
    73 //        getchar();
    74 //    }
    75 //    while(scanf("%s",str1)!=EOF)
    76 //    {
    77 //        int ans=judge(str1);
    78 //        //cout<<str1<<endl;
    79 //        printf("%d
    ",ans);
    80 //    }
    81 //    return 0;
    82 //}

    B题:

    分割字符串

    版本一:使用函数 stringstream (头文件<sstream>)

    https://blog.csdn.net/weixin_35929051/article/details/52502486?tdsourcetag=s_pcqq_aiomsg(stringstream的使用说明)

    #include<iostream>
    #include<stack>
    #include<string>
    #include<cstring>
    #include<sstream>
    #include<stdio.h>
    using namespace std;
    # define ll long long
    const int maxn = 1e6+100;
    int rec[maxn][30];
    int flag[maxn];
    int tot,ans;
    string tmp,str1;
    void add(string str)
    {
        int root=0;
        int len=str.size();
        for(int i=0; i<len; i++)
        {
            int t=str[i]-'a';
            if(!rec[root][t])
                rec[root][t]=++tot;
            root=rec[root][t];
        }
        if(flag[root]==0)
            ans++;
        flag[root]=1;
    }
    void init()
    {
       // memset(flag,0,sizeof(flag));
        for(int i=0; i<=tot; i++)
        {
            flag[i]=0;
            for(int j=0; j<30; j++)
            {
                rec[i][j]=0;
            }
        }
        tot=0,ans=0;
    }
    int main()
    {
        while(getline(cin,str1))
        {
            //cout<<str1<<endl;
            init();
            int p=0,t=0;
            if(str1=="#")
                break;
            stringstream ss(str1);
            while(ss>>str1)
            {
                add(str1);
            }
            cout<<ans<<endl;
           // cout<<tot<<endl;
        }
        return 0;
    }

    版本二:(超时)

    #include<iostream>
    #include<stack>
    #include<string>
    #include<cstring>
    #include<stdio.h>
    using namespace std;
    # define ll long long
    const int maxn = 1e6+100;
    int rec[maxn][30];
    int flag[maxn];
    int tot,ans;
    char tmp[maxn],str1[maxn];
    void add(char *str)
    {
        int root=0;
        int len=strlen(str);
        for(int i=0; i<len; i++)
        {
            int t=str[i]-'a';
            if(!rec[root][t])
                rec[root][t]=++tot;
            root=rec[root][t];
        }
        if(flag[root]==0)ans++;
        flag[root]=1;
    }
    void init()
    {
        for(int i=0; i<=tot; i++)
        {
            flag[i]=0;
            for(int j=0; j<30; j++)
            {
                rec[i][j]=0;
            }
        }
        tot=0,ans=0;
    }
    int main()
    {
        tot=0;
        while(gets(str1))
        {
            init();
            int p=0,t=0;
            if(str1[0]=='#')
                break;
            int len=strlen(str1);
            while(p<len)
            {
                while(str1[p]!=' '&&p<len)
                {
                    tmp[t++]=str1[p];
                    p++;
                }
                while(str1[p]==' '&&p<len)
                p++;
                add(tmp);
                t=0;
            }
            printf("%d
    ",ans);
            getchar();
        }
        return 0;
    }

    01字典树:

    首先输入n个数,然后每次输入一个数k,寻找输入的这个数和前面的n个数中的某一个最大的异或值?也就是k^s最大?

     1 #include <iostream>
     2 #include <string>
     3 #include <deque>
     4 #include <stack>
     5 #include<cmath>
     6 #include <algorithm>
     7 #include<map>
     8 using namespace std;
     9 # define ll long long
    10 # define inf 0x3f3f3f3f
    11 const int maxn = 3e6+100;
    12 ll flag[maxn];
    13 int tot;
    14 int sto[maxn][4];
    15 void init()
    16 {
    17     for(int i=0; i<=tot; i++)
    18     {
    19         flag[i]=0;
    20         for(int j=0; j<3; j++)
    21         {
    22             sto[i][j]=0;
    23         }
    24     }
    25 }
    26 void add(ll t)
    27 {
    28     ll u=0;
    29     for(ll i=32; i>=0; i--)
    30     {
    31         ll tmp=(t>>i)&1;
    32         if(sto[u][tmp]==0)
    33             sto[u][tmp]=++tot;
    34         u=sto[u][tmp];
    35     }
    36     flag[u]=t;
    37 }
    38 ll query(ll t)
    39 {
    40     ll u=0;
    41     for(ll i=32; i>=0; i--)
    42     {
    43         ll tmp=(t>>i)&1;
    44         if(sto[u][tmp^1])
    45             u=sto[u][tmp^1];
    46         else
    47             u=sto[u][tmp];
    48     }
    49     return flag[u];
    50 }
    51 int main()
    52 {
    53     int T;
    54     scanf("%d",&T);
    55     tot=0;
    56     int Case=0;
    57     while(T--)
    58     {
    59         init();
    60         int n,m;
    61         scanf("%d %d",&n,&m);
    62         int tmp;
    63         for(int i=1; i<=n; i++)
    64         {
    65             scanf("%d",&tmp);
    66             add(tmp);
    67         }
    68         printf("Case #%d:
    ",++Case);
    69         for(int i=1; i<=m; i++)
    70         {
    71             scanf("%d",&tmp);
    72             int ans=query(tmp);
    73             printf("%d
    ",ans);
    74         }
    75     }
    76     return 0;
    77 }

    01字典树 

    HDU - 5536 

    具体思路:题目中说的是找三个不同的i,j,k,使得(a[i]+a[j])^a[k]的值最大,那么思路来了,首先第一步,我们先把所有的值全部存到字典树里面,然后两个for循环,每一次先把a[i]和a[j]去掉,然后再去求(a[i]+a[j])在字典树中的最值就可以了。

    AC代码:

      1 #include <iostream>
      2 #include <string>
      3 #include <deque>
      4 #include <stack>
      5 #include<cmath>
      6 #include <algorithm>
      7 #include<map>
      8 using namespace std;
      9 # define ll long long
     10 # define inf 0x3f3f3f3f
     11 # define ll_inf 1ll<<60
     12 const int maxn = 1e6+100;
     13 ll sto[maxn][3];
     14 ll flag[maxn];
     15 ll a[maxn],tot;
     16 ll com[maxn];
     17 ll Max(ll t1,ll t2)
     18 {
     19     if(t1<t2)
     20         return t2;
     21     return t1;
     22 }
     23 void init()
     24 {
     25     for(int i=0; i<=tot; i++)
     26     {
     27         flag[i]=0;
     28         com[i]=0;
     29         for(int j=0; j<3; j++)
     30         {
     31             sto[i][j]=0;
     32         }
     33     }
     34     tot=0;
     35 }
     36 void add(ll t)
     37 {
     38     int u=0;
     39     for(int i=32; i>=0; i--)
     40     {
     41         int tmp=(t>>i)&1;
     42         if(sto[u][tmp]==0)
     43             sto[u][tmp]=++tot;
     44         flag[sto[u][tmp]]++;
     45         u=sto[u][tmp];
     46     }
     47     com[u]=t;//存储这一位上是哪个数
     48 }
     49 void Erase(ll t)
     50 {
     51     int u=0;
     52     for(int i=32; i>=0; i--)
     53     {
     54         int tmp=(t>>i)&1;
     55         flag[sto[u][tmp]]--;//把这个数的路径走过的减去1,就相当于把这个数从树上去掉。
     56         u=sto[u][tmp];
     57     }
     58    // com[u]=0;
     59 }
     60 ll query(ll t)
     61 {
     62     int u=0;
     63     for(int i=32; i>=0; i--)
     64     {
     65         int tmp=(t>>i)&1;
     66         if(sto[u][tmp^1]>0)//看一下当前这一位上是不是有不一样的
     67         {
     68             if(flag[sto[u][tmp^1]]>0)//如果有,就按照不同进行
     69                 u=sto[u][tmp^1];
     70             else// 没有的话,就按照另外一种来进行
     71                 u=sto[u][tmp];
     72         }
     73         else
     74         {
     75             if(flag[sto[u][tmp]]>0)//同理
     76                 u=sto[u][tmp];
     77             else
     78                 u=sto[u][tmp^1];
     79         }
     80     }
     81     return com[u]^t;
     82 }
     83 int main()
     84 {
     85     int T;
     86     tot=0;
     87     scanf("%d",&T);
     88     while(T--)
     89     {
     90         init();
     91         int n;
     92         scanf("%d",&n);
     93         for(int i=1; i<=n; i++)
     94         {
     95             scanf("%lld",&a[i]);
     96             add(a[i]);
     97         }
     98         ll maxx=0;
     99         for(int i=1; i<=n; i++)
    100         {
    101             Erase(a[i]);
    102             for(int j=i+1; j<=n; j++)
    103             {
    104                 Erase(a[j]);
    105                 maxx=Max(maxx,query(a[i]+a[j]));
    106                 add(a[j]);
    107             }
    108             add(a[i]);
    109         }
    110         printf("%lld
    ",maxx);
    111     }
    112     return 0;
    113 }
  • 相关阅读:
    循环取出正则匹配的内容(遍历).
    遍历datatable的方法
    asp.net获取URL和IP地址
    匹配多个字符串方法
    世界杯决赛不好看,有点像假球,被裁判黑了?
    2010南非世界杯冠军预测:荷兰夺冠!
    查了几家人民广场附近的川菜和湘菜馆
    白平衡(转载自wikipedia)
    梦想与感动
    港澳旅游相关备忘
  • 原文地址:https://www.cnblogs.com/letlifestop/p/10262761.html
Copyright © 2011-2022 走看看