hihoCoder:Trie图
来源:互联网 发布:sql join where 区别 编辑:程序博客网 时间:2024/05/10 08:11
详细的文章题目链接如下 :http://hihocoder.com/problemset/problem/1036
这周的题目没有做,现在补上,但是还是要学习一下思路。
题目要求:给出一篇长篇的文章,和一本字典(里面包含了很多英文单词),问那些文章中
那些词语在词典中出现,朴素的做法就是,直接枚举话,假设词语数量为N,每个词语长度为L,
文章的长度为M,时间上要O(N*L*M),
(1)使用Trie树,把所有字典建立起一颗trie树,那么对于文章中的匹配就是从第一个字符串开始,
在trie树中进行路径选择,当找到一个标记节点的时候表示匹配到一个词语;当文章的当前字符
串找不到下一个路径时候,表示第一个字符串开头的不是字典中的词,继续从第二个字符串开始
匹配,依次类推;
(2)显然,在我们匹配的过程中,我们既然已经从str的当前起点i开始匹配了l个长度,那么在枚举str的下一个起点i+1的时候,就意味着最开始的l-1个字符都已经在之前的计算中匹配过了,如果我们能够利用好这个信息的话,就能够大大的减少时间复杂度。”“换句话说,如果我们从str的当前起点开始,匹配了l个长度走到了A结点,如果我们把A结点对应的字符串(即从tree的0号走到A结点的路径)去掉第一个字符,形成一个新的字符串,那么这个字符串肯定是和从str的下一个起点开始,长度为l-1的子串是一样的,而如果我们能够预先找到这个字符串在tree中对应的结点B',我们就不用像之前所说的那样从0号节点走到A结点然后回到0号结点再走到B结点,而是可以直接从0号结点走到A结点然后直接跳转到B’结点然后再根据从str[i+l..k1]这一段走到B结点!”
所以我们的问题规约成了:如何对于一棵给定的Trie树,找到其中每一个结点对应的后缀结点——所谓的后缀
结点就是这个结点在Trie中对应路径去掉第一个字符之后在Trie中对应的结点。
(3)对于一个trie树,可以知道,
根节点(也就是空串),去掉第一个字符之后也是空串;
与根结点相连的,也就是一级结点,去掉第一个字符,也就是他自己本身,所以一级结点的后缀结点是根结点
接着,我们继续看二级结点,显然二级结点的父节点是与他相连的一级结点,他们通过字符串‘x',假设;
那么二级结点的后缀结点就是((一级结点的后缀结点)通过字符串’x‘相连的子节点了)
依次递推,就可以求出所有结点的后缀结点
下面是我的AC代码,脑残了,有些细节写快,纠结两天,睡觉
import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.util.ArrayList;import java.util.Collection;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Scanner;/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. *//** * * @author yuan */public class Main { public static void main(String[] args) throws FileNotFoundException { Scanner cin ; cin = new Scanner(System.in); // FileInputStream ins = new FileInputStream(new File("in")); // cin = new Scanner(ins); int n; n = cin.nextInt();// System.out.println(n); String context = null; TrieMap trieMap = new TrieMap(); for(int i = 0; i < n; ++i){ trieMap.insert(cin.next()); } trieMap.adjustEndNode();// System.out.println(trieMap.foreach()); context = cin.next(); System.out.println(trieMap.find(context) ? "YES" : "NO"); } public static class TrieMap { TrieNode head; public static final int SIZE = 30; public static final int WORDLENGTH = 1001; public TrieMap() { head = new TrieNode(); head.nextNode = head; } public List<String> foreach(){ ArrayList<String> list = new ArrayList<>(); char[] chs = new char[WORDLENGTH]; backTrace(list, this.head, chs, 0); return list; } private void backTrace(List<String> list, TrieNode curNode, char[] chs, int cur){ Collection<TrieNode> children = curNode.children.values(); for(TrieNode node : children){ chs[cur] = node.ch; backTrace(list, node, chs, cur + 1); if(node.isEndNode){ list.add(new String(chs, 0, cur + 1)); } } } public void insert(String str) { char chs[] = str.toCharArray(); TrieNode curNode = this.head; for (int i = 0; i < chs.length; ++i) { TrieNode node = curNode.children.get(chs[i]); if (node == null) { node = new TrieNode(chs[i]); curNode.children.put(chs[i], node); } curNode = node; } curNode.isEndNode = true; } public void adjustEndNode() { LinkedList<TrieNode> queue = new LinkedList<>(); this.head.nextNode = this.head; Collection<TrieNode> children = this.head.children.values(); for(TrieNode node : children){ node.nextNode = this.head; queue.add(node); }// System.out.println(queue); TrieNode curNode = null; while(!queue.isEmpty()){ curNode = queue.removeFirst(); children = curNode.children.values(); for(TrieNode node : children){ node.nextNode = curNode.nextNode.children.get(node.ch); if(node.nextNode == null){ node.nextNode = this.head; } queue.add(node); } } } public boolean find(String str) { boolean flag = false; char[] chs = str.toCharArray(); TrieNode curNode = this.head; TrieNode node = null; for (int i = 0; i < chs.length;++i) { node = curNode.children.get(chs[i]); if (node == null) { node = curNode.nextNode; } else if (node.isEndNode) { flag = true; break; } curNode = node; } return flag; } } public static class TrieNode { boolean isEndNode = false; char ch = ' '; HashMap<Character, TrieNode> children; TrieNode nextNode = null; public TrieNode(Character ch) { this.isEndNode = false; this.ch = ch; this.children = new HashMap<>(TrieMap.SIZE); this.nextNode = null; } public TrieNode() { this(' '); } @Override public String toString(){ return super.toString(); } }}
- hihoCoder:Trie图
- hihocoder #1036 : Trie图
- [HihoCoder]#1036 : Trie图
- #hihocoder 1036 trie图
- hihoCoder #1036 Trie图
- HihoCoder第四周:Trie图
- hihocoder-1036 Trie图(Trie图||AC自动机)
- hihoCoder #1036 : Trie图 (AC自动机)
- hihoCoder 1036 Trie图(AC自动机)
- hihocoder Trie图(AC自动机)
- HiHocoder 1036 : Trie图 AC自动机
- hihoCoder--1036 Trie图(AC自动机)
- hihoCoder 1036 AC自动机 Trie图
- HihoCoder第四周(Trie图)
- hihoCoder 1036 Trie图 AC自动机
- hihocoder 1014 Trie树 trie
- [hihoCoder 1014][Trie 树]Trie
- Trie树 hihoCoder
- uva 10453 - Make Palindrome
- 用iOSOpenDev在Xcode里配置越狱开发环境
- KeyListener的三个方法,而其参数KeyEvent却不同
- <转载>Android软件开发之获取通讯录联系人信息
- Map集合及使用
- hihoCoder:Trie图
- hdu3360National Treasures (最大匹配,拆点法)
- 第一章 关键字
- 在JavaScript 调用C++
- 关于linux oss音频应用编程详解,写的挺好的
- 工作随谈之扯淡
- Android 如何使用ant批量打包
- 第一章 数据类型
- Android Application package 'AndroidManifest.xml' must have a minimum of 2 segments.