`

Trie树判重问题

 
阅读更多

给你100000个长度不超过10的单词。对于每一个单词,我们要判断他出没出现过,如果出现了,第一次出现第几个位置。
这题当然可以用hash来,但是我要介绍的是trie树。在某些方面它的用途更大。比如说对于某一个单词,我要询问它的前缀是否出现过。这样hash就不好搞了,而用trie还是很简单。

   现在回到例子中,如果我们用最傻的方法,对于每一个单词,我们都要去查找它前面的单词中是否有它。那么这个算法的复杂度就是O(n^2)。显然对于100000的范围难以接受。现在我们换个思路想。假设我要查询的单词是abcd,那么在他前面的单词中,以b,c,d,f之类开头的我显然不必考虑。而只要找以a开头的中是否存在abcd就可以了。同样的,在以a开头中的单词中,我们只要考虑以b作为第二个字母的……这样一个树的模型就渐渐清晰了……

   我们可以看到,trie树每一层的节点数是26^i级别的。所以为了节省空间。我们用动态链表,或者用数组来模拟动态。空间的花费,不会超过单词数×单词长度。(转自一大牛)

Trie树的java代码 实现如下:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/** *//**
 * A word trie which can only deal with 26 alphabeta letters.
 * @author Leeclipse
 * @since 2007-11-21
 */

public class Trie{
 
   private Vertex root;//一个Trie树有一个根节点

    //内部类
    protected class Vertex{//节点类
        protected int words;
        protected int prefixes;
        protected Vertex[] edges;//每个节点包含26个子节点(类型为自身)
        Vertex() {
            words = 0;
            prefixes = 0;
            edges = new Vertex[26];
            for (int i = 0; i < edges.length; i++) {
                edges[i] = null;
            }
        }
    }

  
    public Trie () {
        root = new Vertex();
    }

   
    /** *//**
     * List all words in the Trie.
     * 
     * @return
     */

    public List< String> listAllWords() {
       
        List< String> words = new ArrayList< String>();
        Vertex[] edges = root.edges;
       
        for (int i = 0; i < edges.length; i++) {
            if (edges[i] != null) {
                     String word = "" + (char)('a' + i);
                depthFirstSearchWords(words, edges[i], word);
            }
        }        
        return words;
    }

     /** *//**
     * Depth First Search words in the Trie and add them to the List.
     * 
     * @param words
     * @param vertex
     * @param wordSegment
     */

    private void depthFirstSearchWords(List words, Vertex vertex, String wordSegment) {
        Vertex[] edges = vertex.edges;
        boolean hasChildren = false;
        for (int i = 0; i < edges.length; i++) {
            if (edges[i] != null) {
                hasChildren = true;
                String newWord = wordSegment + (char)('a' + i);                
                depthFirstSearchWords(words, edges[i], newWord);
            }            
        }
        if (!hasChildren) {
            words.add(wordSegment);
        }
    }

    public int countPrefixes(String prefix) {
        return countPrefixes(root, prefix);
    }

    private int countPrefixes(Vertex vertex, String prefixSegment) {
        if (prefixSegment.length() == 0) { //reach the last character of the word
            return vertex.prefixes;
        }

        char c = prefixSegment.charAt(0);
        int index = c - 'a';
        if (vertex.edges[index] == null) { // the word does NOT exist
            return 0;
        } else {

            return countPrefixes(vertex.edges[index], prefixSegment.substring(1));

        }        

    }

    public int countWords(String word) {
        return countWords(root, word);
    }    

    private int countWords(Vertex vertex, String wordSegment) {
        if (wordSegment.length() == 0) { //reach the last character of the word
            return vertex.words;
        }

        char c = wordSegment.charAt(0);
        int index = c - 'a';
        if (vertex.edges[index] == null) { // the word does NOT exist
            return 0;
        } else {
            return countWords(vertex.edges[index], wordSegment.substring(1));

        }        

    }

    
    /** *//**
     * Add a word to the Trie.
     * 
     * @param word The word to be added.
     */

    public void addWord(String word) {
        addWord(root, word);
    }

    
    /** *//**
     * Add the word from the specified vertex.
     * @param vertex The specified vertex.
     * @param word The word to be added.
     */

    private void addWord(Vertex vertex, String word) {
       if (word.length() == 0) { //if all characters of the word has been added
            vertex.words ++;
        } else {
            vertex.prefixes ++;
            char c = word.charAt(0);
            c = Character.toLowerCase(c);
            int index = c - 'a';
            if (vertex.edges[index] == null) { //if the edge does NOT exist
                vertex.edges[index] = new Vertex();
            }

            addWord(vertex.edges[index], word.substring(1)); //go the the next character
        }
    }

    public static void main(String args[])  //Just used for test
    {
    Trie trie = new Trie();
    trie.addWord("China");
    trie.addWord("China");
    trie.addWord("China");

    trie.addWord("crawl");
    trie.addWord("crime");
    trie.addWord("ban");
    trie.addWord("China");

    trie.addWord("english");
    trie.addWord("establish");
    trie.addWord("eat");
    System.out.println(trie.root.prefixes);
     System.out.println(trie.root.words);


   
     List< String> list = trie.listAllWords();
     Iterator listiterator = list.listIterator();
     
     while(listiterator.hasNext())
     {
          String s = (String)listiterator.next();
          System.out.println(s);
     }

   
     int count = trie.countPrefixes("ch");
     int count1=trie.countWords("china");
     System.out.println("the count of c prefixes:"+count);
     System.out.println("the count of china countWords:"+count1);

 
    }
}
运行:
C:\test>java   Trie
10
0
ban
china
crawl
crime
eat
english
establish
the count of c prefixes:4
the count of china countWords:4

 

文章来自:http://oivoiv.blog.163.com/

分享到:
评论

相关推荐

    POJ2525-Text Formalization【TrieTree】

    POJ2525-Text Formalization是一个涉及Trie树的经典问题,它教会我们在面对字符串处理时,如何利用Trie树这一高效的数据结构来简化问题。通过理解和实践,不仅可以提升我们的算法能力,还能加深对数据结构应用的洞察...

    海量数据面试题整理txt

    - **Trie树**:Trie树是一种树形结构,特别适合于字符串的检索,可以用来统计不同查询的频率。 例如,在一个每条记录大小为16字节、总大小为1GB的数据集中,可以先将其切分为100个小文件,每个文件10MB大小。然后,...

    网站敏感词过滤Java版.zip

    4. **Aho-Corasick 算法**:在Trie树的基础上增加了失败指针,一次扫描即可匹配所有敏感词,提高了效率。 二、敏感词库 敏感词库通常包含两类词汇:一类是法律规定的禁止词汇,如涉政、涉黄、涉暴等;另一类是企业...

    poj题目分类,关于acm/icpc

    2. **高级数据结构的应用**:使用高级数据结构解决复杂问题,如平衡树用于维护有序集合,Trie树用于高效字符串查询等。 3. **复杂问题解决**:网络流、最优化问题、编码解码、博弈论、图论中的NP完全问题等。 4. **...

    刘汝佳ACM讲义

    “高级数据结构.rar”可能包含更复杂的数据结构,如平衡二叉树(AVL树、红黑树)、Trie树(字典树)、B树、B+树等,它们在高效存储和检索大量数据时有着重要作用。例如,平衡二叉搜索树保证了插入和查找的效率,而B...

    参加ACM大赛应该准备哪些课程?.docx

    5. Trie树:基本概念和应用 6. 左偏树:可合并堆 7. 双端队列:基本概念和应用 数学部分 1. 组合数学:容斥原理、抽屉原理、置换群与Polya定理 2. 递推关系和母函数 3. 数论:素数问题、概率判素算法、概率因子...

    ACM算法模版大集合

    生成树问题 最小生成树 第k小生成树 最优比率生成树 0/1分数规划 度限制生成树 连通性问题 强大的DFS算法 无向图连通性 割点 割边 二连通分支 有向图连通性 强连通分支 2-SAT 最小点基 有向无环...

    《Java面试必知必会》-海量数据类高频问题和参考答案.pdf

    - **处理策略**:分而治之(hash映射)、数据结构优化(如Bloom filter、Bitmap、Trie树、堆、数据库索引等)、分布式处理(Hadoop、MapReduce)。 3. **Bloom Filter** - **应用**:数据判重、集合交集判断。 -...

    JAVA过滤敏感词

    将敏感词插入到Trie树中,之后遍历文本,通过Trie树快速判断每个单词是否是敏感词。 7. **模糊匹配**: 有时候,敏感词可能会被部分替换或变形,这时可以使用模糊匹配。例如,使用Levenshtein距离计算文本与敏感词...

    国家集训队2000论文集

    2. **数据结构**:链表、数组、栈、队列、树(二叉树、平衡树、堆)、图等基本数据结构的使用,以及高级数据结构如红黑树、B树、Trie树等。 3. **编程语言**:通常以C++为主,涉及面向对象编程、模板类、STL(标准...

    java实现敏感词过滤

    3. **Trie树(字典树)**:敏感词库构建为Trie树结构,可以快速查找是否存在敏感词。插入和查找的时间复杂度都是O(m),m为敏感词长度,适合大量敏感词的情况。 4. **Aho-Corasick算法**:基于Trie树的优化,可以在...

    data structures for text sequences.zip

    后缀树是一种高效的数据结构,用于处理字符串的模式匹配问题。它能快速查找字符串的所有子串,常用于生物信息学中的DNA序列分析和文本索引。 六、Patricia Trie(PAT树) PAT树是优化后的Trie结构,减少了节点数量...

    十道海量数据处理面试题(卷).docx

    这些题目覆盖了海量数据处理的关键技术,包括数据结构(如Trie树、Bloom Filter、Bitset)、排序算法(如基数排序、快速排序)、分布式计算框架(如MapReduce)、空间效率优化(如Top-K、布隆过滤器)等。...

    百度实习招聘软件研发试题

    首先,使用Trie树存储字典中的所有单词,这样可以在O(L)的时间复杂度内搜索任意长度为L的单词。其次,对于每个插入的单词,构建一个Hash表来记录每个单词字符的频率分布,这有助于快速识别兄弟单词。 **查询流程:*...

    参加ACM大赛应该准备哪些课程? (2).docx

    1. 广搜的状态优化:利用 M 进制数存储状态、转化为串用 hash 表判重、按位压缩存。 2. 深搜的优化:尽量用位运算、一定要加剪枝、函数参数尽可能少、层数不易过大。 八、动态规划 1. 需要用数据结构优化的动态...

    参加ACM大赛应该准备哪些课程?.pdf

    10. 素数问题、概率判素算法、概率因子分解 数据结构 1. 二叉堆 2. 左偏树 3. 二项树 4. 胜者树 5. 跳跃表 6. 样式图 7. 斜堆 8. Hash 表 9. 并查集 10. 路径压缩思想的应用 STL 中的数据结构 1. vector 2. ...

    POJ2525–Text Formalization 测试数据

    在编程实践中,我们可以采用动态规划、贪心、分治等算法思想,结合数据结构如哈希表、Trie树、字典树等来提高效率。此外,利用已有的自然语言处理库,如NLTK、spaCy等,也可以简化某些步骤的实现。 总的来说,POJ...

    ACM算法模板和pku代码

    Trie树 二叉查找树 线段树 RMQ LCA+RMQ SB-Tree 数论 生成紧凑素数表 分解质因子 最大公约数 a^b mod n 扩张欧几里德算法 素数表质因子分解 Stirling公式 中国剩余定理 欧拉数(递推法) 欧拉数(公式...

    ACM超强代码,不同的解法

    6. **数据结构**:如堆(优先队列)、平衡二叉搜索树(AVL、红黑树)、字典树(Trie)等,用于高效地进行查找、插入和删除操作。 7. **模拟**:对于某些问题,可能需要编写程序模拟特定过程,如游戏策略、物理过程...

Global site tag (gtag.js) - Google Analytics