学习了 cracking code interview 18.8 之后的整理。
用后缀树(Suffix Trie)寻找长字符串S中所有出现的子串T
原理: 如果T为S的子串, 那么T一定是S某个后缀的前缀(或本身); 后缀树的root必须为空
时间复杂度:构造树 O(ns^2)
查找 O(nt)
1. 后缀树类, 后缀树存了字符串S所有的后缀
public class SuffixTreeNode {
// 当前root的孩子们
// 若为英语小写字母,则最多有26个孩子
HashMap<Character, SuffixTreeNode> children
= new HashMap<Character, SuffixTreeNode>();
char value; // 当前节点的值
// 存该后缀出现的起始位置,即多模式查找的结果
// exp: S = bibs, T = b, 则 节点b的 indexes = [0,3]
ArrayList<Integer> indexes = new ArrayList<Integer>();
public SuffixTreeNode(){}
public void insertString(String s, int index){
indexes.add(index); // 添加当前index
if(s != null && s.length() > 0){
value = s.charAt(0);
SuffixTreeNode child = null;
// 若root已经有这个value的孩子了,则将后缀附加到这个子节点树上
if(children.containsKey(value)){
child = children.get(value);
}else{
child = new SuffixTreeNode();
children.put(value, child);
}
String remainder = s.substring(1);
// 递归添加后缀
child.insertString(remainder, index);
}
}
public ArrayList<Integer> search(String s){
if(s == null || s.length() == 0)
return indexes;
else{
char first = s.charAt(0);
if(children.containsKey(first)){
String remainder = s.substring(1);
return children.get(first).search(remainder);
}
}
return null;
}
}
2. 构造S的后缀树 - O(ns^2)
public class SuffixTrie {
// 后缀树的根节点必须为空
SuffixTreeNode root = new SuffixTreeNode();
// 构造S的后缀树
public SuffixTrie(String s){
for(int i = 0; i < s.length(); i++){
String suffix = s.substring(i);
root.insertString(suffix, i);
}
}
public ArrayList<Character> search(String t){
return root.search(t);
}
}
3. 使用后缀树查找
public ArrayList<Integer> findSubStr(String s, String t){
SuffixTrie trie = new SuffixTrie(s);
return trie.search(t);
}