zoukankan      html  css  js  c++  java
  • Trie字典树 基本操作

    Trie字典树

    先看一道例题

    给出 n n n个字符串,以及 m m m个询问。每次询问读入一个字符串,求该字符串是多少个字符串的前缀。
    每个字符串长度小于 1 0 2 10^2 102,n和m小于 1 0 5 10^5 105

    【输入】
    4
    anan
    amn
    aman
    anann
    3
    ana
    ama
    a

    【输出】
    2
    1
    4

    朴素算法:暴力搜索,对于每个询问,把所有的n个字符串搜索一遍,统计答案。时间复杂度大于 1 0 10 10^{10} 1010。显然,这样时间是非常大的。

    所以我们需要使用字典树

    什么是字典树?

    字典树,顾名思义,首先它是一棵树。
    而且它是用来储存字符串的!!!
    它的根节点为空,其余每个节点代表一个字符。从根节点开始,沿着一定的路径,加上沿途遇到的字符,到达每个节点,都能得到对应的一个字符串。

    建树

    f [ i ] [ c ] f[i][c] f[i][c]表示字典树中编号 i i i节点的儿子中,表示字符 c c c的儿子的编号。
    为了节约空间,只有建树时需要用到的节点,才会被开启,其余都是不存在的。(这句话如果不好理解可以看看操作步骤和代码)

    当前我们将字符串 s [ k ] s[k] s[k]加入字典树,步骤如下:
    1、字符串从左往右,对应地从字典树的根节点开始往下走;
    2、如果当前的 f [ i ] [ s [ k ] [ j ] ] f[i][s[k][j]] f[i][s[k][j]]为0,说明这个节点还未被开启,将节点总数 n u m + 1 num+1 num+1,然后 f [ i ] [ s [ k ] [ j ] ] = n u m f[i][s[k][j]]=num f[i][s[k][j]]=num
    3、继续往下走到对应的儿子节点。 i = f [ i ] [ s [ k ] [ j ] ] i=f[i][s[k][j]] i=f[i][s[k][j]] j + 1 j+1 j+1
    4、当走完整个字符串时,给当前的节点 i i i k k k连一条边,表示字符串 s [ k ] s[k] s[k]的终点在节点 i i i

    建树可以用递归实现,也可以用循环实现。以下贴上递归代码,循环类似。

    	void make(int i,int j)
    	{
    		if(j==slen) 
    		{
    			add(i,k);
    			return;
    		}
    		else
    		{
    			if(f[i][s[k][j]]==0) f[i][s[k][j]]=++num;
    			dfs(f[i][s[k][j]],j+1);
    		}
    	}
    
    	for(k=1;k<=n;k++)
    	{
    		scanf("%s",s[k]");
    		slen=strlen(s[k]);
    		make(0,0);
    	}
    

    效果图

    如前面的样例,四个字符串用字典树储存的效果。
    anan
    amn
    aman
    anann
    这里写图片描述

    优势

    由上图显而易见,当多个字符串有相同前缀时,相同的字符只会储存一次,节省了很大的空间。
    同时,用字典树储存字符串,可以对许多关于字符串前缀的题目有很大帮助。

    回到例题

    显然,这题我们需要先用 n n n个字符串建立一棵字典树。
    与此同时,记录 s u m [ i ] sum[i] sum[i]表示 n n n个字符串中前缀为 s t r i n g [ i ] string[i] string[i]的个数, s t r i n g [ i ] string[i] string[i]为字典树中到节点 i i i处所表示的字符串(此处只是为了方便说明,在实现时这个 s t r i n g string string数组并不存在)。每到一个节点 i i i,就给 s u m [ i ] + 1 sum[i]+1 sum[i]+1

    如何处理询问?
    将询问串放入字典树中,类似建树的方式往下走。如果对应的节点不存在,则直接返回并输出 0 0 0.
    否则一直走到该串的末尾,对应的 s u m [ i ] sum[i] sum[i]即为答案。

    结束语

    此时,相信你已经学会了。字典树模板都是一样的,对于不同的题目不同的要求,都以模板为基础,再按需添加各种操作,难题便迎刃而解。
    面对更多的困难与挑战,需要你更多思考、灵活变通,一切都不是问题!

    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    Java程序设计之算出一年第多少天
    Java程序设计之打印100~999的水仙花数
    AJAX提交方法(POST)Demon
    AJAX提交方法(GET)Demon
    java程序设计线程池(newCachedThreadPool())
    java线程池(newSingleThreadExecutor())小应用
    Java程序设计之线程池应用
    java程序设计之反弹高度
    java程序设计之完数
    iOS UIView 基本属性用法
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910124.html
Copyright © 2011-2022 走看看