leetcode第208题实现前缀树
class Trie {
private TrieNode root;
private static class TrieNode {
boolean isEnd;
TrieNode[] children;
public TrieNode() {
this.children = new TrieNode[26];
this.isEnd = false;
}
}
/**
* Initialize your data structure here.
*/
public Trie() {
this.root = new TrieNode();
}
/**
* Inserts a word into the trie.
*/
public void insert(String word) {
if (word == null || word.length() == 0) {
return;
}
TrieNode tmpRoot = root;
int curson = 0;
while (true) {
boolean isContain = containsChar(tmpRoot, word.charAt(curson));
//前缀树中包含当前字符
if (!isContain) {
//将剩余的字符串中的字符插入到前缀树中
insertTheOtherTrieNode(tmpRoot, word, curson);
break;
} else {
tmpRoot = searhNodeByCh(tmpRoot, word.charAt(curson));
}
curson++;
if (curson > word.length() - 1) {
tmpRoot.isEnd = true;
break;
}
}
}
/**
* Returns if the word is in the trie.
*/
public boolean search(String word) {
if (word == null || word.length() == 0) {
return false;
}
TrieNode tmpRoot = root;
for (int i = 0; i < word.length(); i++) {
TrieNode child = searhNodeByCh(tmpRoot, word.charAt(i));
if (child == null) {
return false;
}
tmpRoot = child;
}
return tmpRoot.isEnd ? true : false;
}
/**
* Returns if there is any word in the trie that starts with the given prefix.
*/
public boolean startsWith(String prefix) {
if (prefix == null || prefix.length() == 0) {
return false;
}
TrieNode tmpRoot = root;
for (int i = 0; i < prefix.length(); i++) {
TrieNode child = searhNodeByCh(tmpRoot, prefix.charAt(i));
if (child == null) {
return false;
}
tmpRoot = child;
}
return true;
}
//判断当前节点的子节点是否包含这个字符
private boolean containsChar(TrieNode parent, char ch) {
return searhNodeByCh(parent, ch) != null;
}
private int calPos(char ch) {
return Integer.valueOf(ch) - Integer.valueOf('a');
}
private TrieNode searhNodeByCh(TrieNode parent, char ch) {
TrieNode[] children = parent.children;
int pos = calPos(ch);
return children[pos];
}
private TrieNode insertTrieNode(TrieNode parent, char ch) {
TrieNode[] children = parent.children;
int pos = calPos(ch);
TrieNode node = new TrieNode();
children[pos] = node;
return node;
}
private void insertTheOtherTrieNode(TrieNode parent, String word, int startIndex) {
while (true) {
TrieNode trieNode = insertTrieNode(parent, word.charAt(startIndex));
parent = trieNode;
startIndex++;
if (startIndex > word.length() - 1) {
trieNode.isEnd = true;
break;
}
}
}
}
初始化前缀树的时间复杂度是O(m*n),m为字符串的个数,n为插入的字符串的数据规模。查询是否包含某个字符串的时间复杂度为O(logn)。
leetcode第2097题多次搜索
给定一个较长字符串big和一个包含较短字符串的数组smalls,设计一个方法,根据smalls中的每一个较短字符串,对big进行搜索。输出smalls中的字符串在big里出现的所有位置positions,其中positions[i]为smalls[i]出现的所有位置。
class Solution {
private Trie trie;
public Solution() {
this.trie = new Trie();
}
public int[][] multiSearch(String big, String[] smalls) {
if (smalls == null || smalls.length == 0 ) {
return new int[0][0];
}
if (big== null || big.length() == 0) {
return new int[smalls.length][0];
}
int[][] result = new int[smalls.length][];
List<Integer> recordList = new ArrayList<>();
//使用smalls构建前缀树
for (int i = 0; i < smalls.length; i++) {
trie.insert(smalls[i], i);
recordList.add(i);
}
Map<Integer, List<Integer>> tmpResultMap = new HashMap<>();
for (int i = 0; i < big.length(); i++) {
List<Trie.TrieNode> trieNodes = trie.search(i, big, trie.root);
List<Integer> indexList = new ArrayList<>();
for (Trie.TrieNode node : trieNodes) {
indexList.add(node.arrIndex);
}
tmpResultMap.put(i, indexList);
}
Map<Integer, List<Integer>> resultMap = new HashMap<>();
//整理
for (Map.Entry<Integer, List<Integer>> entry : tmpResultMap.entrySet()) {
Integer key = entry.getKey();
List<Integer> values = entry.getValue();
for (Integer value : values) {
if (resultMap.get(value) == null) {
List<Integer> keyList = new ArrayList<>();
keyList.add(key);
resultMap.put(value, keyList);
} else {
resultMap.get(value).add(key);
}
}
}
for (Map.Entry<Integer, List<Integer>> entry : resultMap.entrySet()) {
Integer key = entry.getKey();
List<Integer> values = entry.getValue();
result[key] = new int[values.size()];
for (int i = 0; i < values.size(); i++) {
result[key][i] = values.get(i);
}
recordList.remove(key);
}
for (Integer record : recordList) {
result[record] = new int[0];
}
return result;
}
public static class Trie {
private TrieNode root;
public static class TrieNode {
private Integer arrIndex;
private boolean isEnd;
private TrieNode[] children;
public TrieNode() {
this.children = new TrieNode[26];
}
}
public Trie() {
this.root = new TrieNode();
}
public void insert(String word, int arrIndex) {
if (word == null || word.length() == 0) {
return;
}
TrieNode tmpRoot = root;
int curson = 0;
while (true) {
boolean isContain = containsChar(tmpRoot, word.charAt(curson));
//前缀树中包含当前字符
if (!isContain) {
//将剩余的字符串中的字符插入到前缀树中
insertTheOtherTrieNode(tmpRoot, word, curson, arrIndex);
break;
} else {
tmpRoot = searhNodeByCh(tmpRoot, word.charAt(curson));
}
curson++;
if (curson > word.length() - 1) {
tmpRoot.arrIndex = arrIndex;
tmpRoot.isEnd = true;
break;
}
}
}
public List<TrieNode> search(int index, String word, TrieNode tmpRoot) {
if (word == null || word.length() == 0) {
return null;
}
List<TrieNode> trieNodes = new ArrayList<>();
while (index < word.length()) {
TrieNode trieNode = searhNodeByCh(tmpRoot, word.charAt(index));
if (trieNode != null && trieNode.arrIndex != null) {
trieNodes.add(trieNode);
}
if (trieNode == null) {
break;
}
tmpRoot = trieNode;
index++;
}
return trieNodes;
}
//判断当前节点的子节点是否包含这个字符
private boolean containsChar(TrieNode parent, char ch) {
return searhNodeByCh(parent, ch) != null;
}
private int calPos(char ch) {
return Integer.valueOf(ch) - Integer.valueOf('a');
}
private TrieNode searhNodeByCh(TrieNode parent, char ch) {
TrieNode[] children = parent.children;
int pos = calPos(ch);
return children[pos];
}
private TrieNode insertTrieNode(TrieNode parent, char ch) {
TrieNode[] children = parent.children;
int pos = calPos(ch);
TrieNode node = new TrieNode();
children[pos] = node;
return node;
}
private void insertTheOtherTrieNode(TrieNode parent, String word, int startIndex, int arrIndex) {
while (true) {
TrieNode trieNode = insertTrieNode(parent, word.charAt(startIndex));
parent = trieNode;
startIndex++;
if (startIndex > word.length() - 1) {
trieNode.arrIndex = arrIndex;
trieNode.isEnd = true;
break;
}
}
}
}
}
查询的时间复杂度为O(m*logn),m为大字符串的长度,n为小字符串数组某一字符串的长度。