zoukankan      html  css  js  c++  java
  • 【String】字典树

    字典树

    字典树(Trie)是一个用来处理字符串的数据结构

    字典树的建树的大概流程

    新建一个没有内容(不储存任何字符)的结点,用来做起点

    把每一个字符串的每一个位置看成是单独的一层,如果在某一个位置上有没有这个字母,如果没有的话,就在这一层新建一个能够代表这个字母意义的结点;如果有的话,就将上一层的结点连上这一层的这个结点。

    字典树的代码实现

    首先,在字典树的代码实现中,我们会使用一个next数组。

    比如next[i][j](其中0<=j<=25,从小到大依次代表,a,b,c,d,e,f,...,z),代表的是第i个结点的下一个结点为字母j的结点标号。

    其中next[i][j]==0代表以第i个结点的下一个储存内容为j的结点并没有存在。

    因而我们需要对整个next数组做一个初始化

    void init()
    {
        memset(next.0,sizeof(next));
    }
    

    (有点类似链式前向星)

    处理一个字符串的函数

    void insert(const string &s)
    {
         int cur = 1;//代表的是没有意义的那一个头结点
         for(int i=0;i<s.length();i++)
         {
              if(!next[cur][s[i]-'a'])
                 next[cur][c-'a']=++cnt; //如果没有就临时创建一个结点,并赋予这个结点一个编号
              cur = next[cur][c-'a']; //游标跑到下一个结点
         }
         //ed[cur]++;
    }
    

    查询某个前缀是否存在(看一下这个字符串能否在当前的字典树跑得完?)

    同时cur最终停止的位置代表的是一个字符串末尾字符的位置,由于字典树造树的特性,我们可以知道最终的cur即代表着一个字符串。可以开一个数组ed去记录某种字符串的数量。

    从不存储任何字母信息的结点(cur=1)开始,如果当前的结点连接到的下一个结点并没有存在的话,那么就直接返回false,否则就继续向下搜索,直到搜索完毕并且在搜索的过程中并没有产生任何的问题,那就返回true。

    bool find_prefix(const string &s)
    {
          int cur = 1; //修正到起点
          for(int i=0;i<=s.length();i++)
          {
              if(!next[cur][ s[i]-'a' ])
                 return false;
              cur = next[cur][c-'a'];
          }
          return true;
    }
    

    例题

    AcWing 142. 前缀统计

    image

    #include <bits/stdc++.h>
    #define rep(i,x,n) for(int i=x;i<n;i++)
    #define repd(i,x,n) for(int i=x;i<=n;i++)
    using namespace std;
    const int N = 1E5+10;
    int n,m,cnt,ed[N],tr[N][26];
    vector<string > vecs;
    void init()
    {
    	memset(tr,0,sizeof(tr));
    	cnt=2;
    }
    void build(const string &s)
    {
    	int cur=1;
        for(int i=0;i<s.length();i++)
        {
        	if(!tr[cur][ s[i]-'a' ])
        		tr[cur][ s[i]-'a' ]=cnt++;
        	cur=tr[cur][ s[i]-'a' ];
    	}
    	ed[cur]++;
    }
    int find_prefix(const string &s)
    {
    	int cur=1,res=0;
    	for(int i=0;i<s.length();i++)
    	{
    		cur=tr[cur][ s[i]-'a' ];
    		res += ed[cur];
    	}
    	return res;
    }
    int main()
    {
    	init();
        cin>>n>>m;
        string s;
        for(int i=1;i<=n;i++)
        {
        	cin>>s;
        	build(s);
    	}
            
        int res;
    	for(int i=1;i<=m;i++)
    	{
    		cin>>s;
    		cout<<find_prefix(s)<<endl;
    	}
        return 0;
    }
    
    
  • 相关阅读:
    spring注解集合
    spring工作原理理解
    Linux下mysql命令 导入 导出sql文件
    List和Set排序的实现
    LeetCode--树
    LeetCode--链表
    LeetCode--字符串
    LeetCode--贪心算法
    LeetCode--数组
    数据库编程基本练习题
  • 原文地址:https://www.cnblogs.com/BeautifulWater/p/15267700.html
Copyright © 2011-2022 走看看