为什么80%的码农都做不了架构师?>>>   

Add and Search Word - Data structure design

问题:

Design a data structure that supports the following two operations:

void addWord(word)
bool search(word)

search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means it can represent any one letter.

For example:

addWord("bad")
addWord("dad")
addWord("mad")
search("pad") -> false
search("bad") -> true
search(".ad") -> true
search("b..") -> true

Note:
You may assume that all words are consist of lowercase letters a-z.

 hint:

You should be familiar with how a Trie works. If not, please work on this problem: Implement Trie (Prefix Tree) first.

解决:

① 要求实现添加和查找单词,实际上是实现向字典树种添加词组,并可以查找匹配词组。与 Implement Trie (Prefix Tree) 相似,这道题里面'.'可以代替任意字符,所以一旦有了'.',就需要查找所有的子树,只要有一个返回true,整个search函数就返回true。

class TrieNode{//222ms
    char c;//当前节点的字符
    Map<Character,TrieNode> children = new HashMap<>();//当前节点的子节点,以当前节点的字符作为key
    boolean isLeaf;
    public TrieNode(){}
    public TrieNode(char c){
        this.c = c;
    }
}
public class WordDictionary{
    private TrieNode root;//指定根节点,没有字符。
    public WordDictionary(){
        root = new TrieNode();//根节点没有字符
    }
    public void addWord(String word){
        Map<Character,TrieNode> cur = root.children;//从根节点的子节点开始向下添加
        for (int i = 0;i < word.length() ;i ++ ) {
            char c = word.charAt(i);//当前要插入的字符
            TrieNode tmp = null;//对应的节点
            if (cur.containsKey(c)) {//当前字符对应的节点已经存在了
                tmp = cur.get(c);//获取遍历到的节点
            }else{
                tmp = new TrieNode(c);
                cur.put(c,tmp);
            }
            cur = tmp.children;
            if (i == word.length() - 1) {
                tmp.isLeaf = true;
            }
        }
    }
    public boolean search(String word){
        return dfsSearch(root.children,word,0);
    }
    public boolean dfsSearch(Map<Character,TrieNode> cur,String word,int i){
        if (i == word.length()) {
            if (cur.size() == 0) {//节点与单词都遍历完了
                return true;
            }else{
                return false;
            }
        }
        char c = word.charAt(i);
        if (cur.containsKey(c)) {
            if (i == word.length() - 1 && cur.get(c).isLeaf) {
                return true;
            }
            return dfsSearch(cur.get(c).children,word,i + 1);
        }else if(c == '.'){
            boolean res = false;
            for (Map.Entry<Character,TrieNode> child : cur.entrySet()) {
                if (i == word.length() - 1 && child.getValue().isLeaf) {
                    return true;
                }
                if(dfsSearch(child.getValue().children,word,i + 1)){
                    res = true;
                }
            }
            return res;
        }else{
            return false;
        }
    }
}

② 使用数组代替Map。

class TrieNode{//186ms
    TrieNode[] children;
    boolean isLeaf;
    public TrieNode(){//单词中全部为26个小写字母。
        children = new TrieNode[26];
    }
}
public class WordDictionary {
    TrieNode root;
    public WordDictionary(){
        root = new TrieNode();//根节点为空
    }
    public void addWord(String word){
        TrieNode cur = root;
        for (int i = 0;i < word.length() ;i ++ ) {//构造前缀树
            char c = word.charAt(i);
            int index = c - 'a';//在孩子节点中的位置
            if (cur.children[index] == null) {
                TrieNode tmp = new TrieNode();
                cur.children[index] = tmp;
                cur = tmp;
            }else{
                cur = cur.children[index];
            }
        }
        cur.isLeaf = true;
    }
    public boolean search(String word){
        return dfsSearch(root,word,0);
    }
    public boolean dfsSearch(TrieNode cur,String word,int i){
        if (i == word.length() && cur.isLeaf) {
            return true;
        }
        if (i >= word.length()) {
            return false;
        }
        char c = word.charAt(i);
        if (c == '.') {
            boolean res = false;
            for (int j = 0;j < 26 ;j ++ ) {//查看是否有匹配的子节点
                if (cur.children[j] != null) {
                    if (dfsSearch(cur.children[j],word,i + 1)) {
                        res = true;
                        break;
                    }
                }
            }
            if (res) {
                return true;
            }
        }else{
            int index = c - 'a';
            if (cur.children[index] != null) {
                return dfsSearch(cur.children[index],word,i + 1);
            }else{
                return false;
            }
        }
        return false;
    }
}

③ 在discuss中看到的,使用map保存节点及其对应路径上的长度,值为字符串的长度,键为对应的字符串的长度。

public class WordDictionary{//160ms
    //使用map构造前缀树,使用链表保存节点值.键为字符串长度,值为对应的字符串
    Map<Integer,List<String>> map = new HashMap<>();
    public void addWord(String word){
        int index = word.length();
        if (! map.containsKey(index)) {
            List<String> list = new ArrayList<>();
            list.add(word);
            map.put(index,list); 
        }else{
            map.get(index).add(word);
        }
    }
    public boolean search(String word){
        int index = word.length();
        if(! map.containsKey(index)){
            return false;
        }
        List<String> list = map.get(index);
        for (String s : list) {
            if (isSame(s,word)) {
                return true;
            }
        }
        return false;
    }
    public boolean isSame(String root,String search){
        if (root.length() != search.length()) {
            return false;
        }
        for (int i = 0;i < root.length() ;i ++ ) {
            if (search.charAt(i) != '.' && search.charAt(i) != root.charAt(i)) {
                return false;
            }
        }
        return true;
    }
}

转载于:https://my.oschina.net/liyurong/blog/1575284

【字典树】添加和查找单词相关推荐

  1. Tire树(字典树-字符串快速查找)

    前言 一.Tire树是什么? 二.怎么建立tire树 1.字符串插入Tire树入 2.查找字符串 总结 前言: 最近是在复习基础算法,正好复习到了数据结构,所以写了自己对Tire树的理解,数据结构对我 ...

  2. 字典树c语言,字典树的应用 单词意义查找-C语言实现

    下面是编程之家 jb51.cc 通过网络收集整理的代码片段. 编程之家小编现在分享给大家,也给大家做个参考. 实现根据单词快速找到对应的解释 /* 字典树应用,快速单词查找 */ const int ...

  3. c语言 trie树,C语言实现Trie树(字典树)的插入查找删除与遍历操作

    Trie树,也称作是字典树,是一种哈希树的变种,查询效率较高.Trie树可以用于统计或者排序大量的字符串,比如对一系列字符串按照字典序排序. 字典树是一个多叉树,每一个节点上存储的不是一个字符串,而是 ...

  4. 【前缀树】C++ 数据结构 字典树

    之前有段时间力扣天天出字典树,当时写得特别熟练,几个月没做都忘得差不多了--今天又出了相关题目,正好复习一下. 文章目录 一.前缀树是什么? 二.实现前缀树 三.例题:添加与搜索单词 总结 一.前缀树 ...

  5. 字典树Trim详解+相关例题---龙之介算法基础课

    字典树,顾名思义,是关于"字典"的一棵树. 即:它是对于字典的一种存储方式(所以是一种数据结构而不是算法). 这个词典中的每个"单词"就是从根节点出发一直到某一 ...

  6. Trie(字典树/前缀树)

    字典树/前缀树 Trie(发音类似 "try")或者说 前缀树(字典树) 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键.这一数据结构有相当多的应用情景,例如自动补完和 ...

  7. #1117. 编码 ( 字典树版 ) 题解分析

    [问题描述] 我们准备根据一份文本编码表对一篇文本进行压缩.编码表的每一项包含两个部分:要编码的字符串和对应的编码.编码是二进制的01串,用来替代文本中相应的字符串以实现压缩编码的目的.这些01串不一 ...

  8. 字典树 ZOJ1109 HDU1251 PKU1204 HDU1075

    又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:利用字符串的公共前缀 ...

  9. Kiner算法刷题记(二十一):字典树与双数组字典树(数据结构基础篇)

    字典树与双数组字典树(数据结构基础篇) 系列文章导引 系列文章导引 开源项目 本系列所有文章都将会收录到GitHub中统一收藏与管理,欢迎ISSUE和Star. GitHub传送门:Kiner算法算题 ...

最新文章

  1. 阿里云智能 AIoT 首席科学家丁险峰:阿里全面进军IoT这一年 | 问底中国IT技术演进...
  2. 图论 ---- dijkstra变种dp Codeforces Div2 703 E. Paired Payment
  3. autofs一个神奇的服务
  4. 遍历Collection,避免在循环中删除对象时避免ConcurrentModificationException
  5. Appium 命令行安装教程
  6. 关于初学Go的一些总结
  7. PRISM概率模型检测器初使用--骰子模型(改进版)
  8. IBATISNETNET 1.3 开发指南系列文章
  9. PAT (Advanced Level) 1003 Emergency(最短路+动态规划)
  10. 今天会议的召开,和你有关系吗?
  11. linux中内存挂载到目录下
  12. VMware View虚拟桌面在安卓平板电脑上的演示
  13. Spring Boot 2.x 集成 Quartz 定时器 jdbc 持久化、配置集群
  14. 谷歌地球看不了街景_PPT放入3D模型之后,居然能模拟谷歌地图!
  15. iOS 常用正则表达式一览表
  16. 中国人为何无缘诺贝尔奖
  17. 开源python语音识别_5 款不错的开源语音识别/语音文字转换系统
  18. android 自定义 snackbar,Android Study Material Design 五 之:自定义Toast以及玩转SnackBar...
  19. Profibus-Dp 工作过程介绍
  20. “一起吧”低调上线,百度社交还有机会吗?

热门文章

  1. Laravel 深入核心系列教程
  2. linux系统监控命令汇总
  3. Linux ubuntu 切换阿里更新源
  4. CUDNN v3特性
  5. WEB控件没有什么所谓好不好,而是用得好不好
  6. 0927_C/C++笔试题_10:16道c语言面试例子【2】
  7. 老是说我编译版本不够_编译etcd出现的cannot load bufio的错误解决办法
  8. 经典仿句100例_(完整版)精美句子仿写100例
  9. Android编程之LocalBroadcastManager源码详解
  10. windows下git安装