详细的文章题目链接如下 :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();
}
}
}