Trie
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public int[][] indexPairs(String text, String[] words) {
TrieNode root = new TrieNode();
for (String w : words) {
insert(root, w);
}
List<int[]> list = new ArrayList<>();
for (int i = 0; i < text.length(); i++) {
TrieNode node = root;
for (int j = i; j < text.length(); j++) {
node = node.children[text.charAt(j) - 'a'];
if (node == null) {
break;
}
if (node.end) {
list.add(new int[]{i, j});
}
}
}
int[][] result = new int[list.size()][2];
for (int i = 0; i < result.length; i++) {
result[i] = list.get(i);
}
return result;
}
class TrieNode {
TrieNode[] children = new TrieNode[26];
boolean end = false;
}
private void insert(TrieNode root, String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
if (node.children[c - 'a'] == null) {
node.children[c - 'a'] = new TrieNode();
}
node = node.children[c - 'a'];
}
node.end = true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
private TrieNode root = new TrieNode();
public WordFilter(String[] words) {
for (int i = 0; i < words.length; i++) {
String w = words[i];
for (int j = w.length(); j >= 0; j--) {
// '{' - 'a' == 27
insert(root, w.substring(j) + "{" + w, i);
}
}
}
public int f(String prefix, String suffix) {
String s = suffix + "{" + prefix;
TrieNode node = root;
for (char c : s.toCharArray()) {
if (node.children[c - 'a'] == null) {
return -1;
}
node = node.children[c - 'a'];
}
return node.index;
}
class TrieNode {
TrieNode[] children;
int index; // index in the dictionary. Larger index overwrites the old one.
TrieNode() {
children = new TrieNode[27];
index = 0;
}
}
private void insert(TrieNode root, String word, int index) {
TrieNode node = root;
for (char c : word.toCharArray()) {
if (node.children[c - 'a'] == null) {
node.children[c - 'a'] = new TrieNode();
}
node = node.children[c - 'a'];
node.index = index;
}
}
Implement Trie II (Prefix Tree)
1
2
3
4
5
6
7
8
9
10
11
class TrieNode {
TrieNode[] children;
int prefixCount;
int wordCount;
TrieNode() {
children = new TrieNode[26];
prefixCount = -1;
wordCount = -1;
}
}
Prefix Sum
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// key : val
private Map<String, Integer> map = new HashMap<>();
private TrieNode root = new TrieNode();
/** Initialize your data structure here. */
public MapSum() {
}
public void insert(String key, int val) {
int delta = val - map.getOrDefault(key, 0);
map.put(key, val);
TrieNode node = root;
node.sum += delta;
for (char c: key.toCharArray()) {
node.children.putIfAbsent(c, new TrieNode());
node = node.children.get(c);
node.sum += delta;
}
}
public int sum(String prefix) {
TrieNode node = root;
for (char c: prefix.toCharArray()) {
node = node.children.get(c);
if (node == null) {
return 0;
}
}
return node.sum;
}
class TrieNode {
Map<Character, TrieNode> children;
// sum of all the pairs' value whose key starts with the prefix
// where prefix is from root to this node
int sum;
TrieNode() {
children = new HashMap<>();
sum = 0;
}
}
Virtual Trie
K-th Smallest in Lexicographical Order
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public int findKthNumber(int n, int k) {
int curr = 1;
while (k > 1) {
// counts the nodes between the current node and its next node on the same level
int count = countNodes(n, curr, curr + 1);
if (count < k) {
// moves to curr + 1
curr++;
k -= count;
} else {
// the k-th integer is in the subtree of current node
// goes to the leftmost child node
curr *= 10;
k--;
}
}
return curr;
}
// counts the nodes in [node1, node2)
// node1 and node2 are in the same subtree and on the same level
public int countNodes(int n, long node1, long node2) {
int count = 0;
while (node1 <= n) {
// if node2 > n, n is in the range [node1, node2).
// adds (n - node1 + 1) to the count
// else the subtree of node1 is complete.
// adds (node2 - node1) to the count
count += Math.min(n + 1, node2) - node1;
// next level
node1 *= 10;
node2 *= 10;
}
return count;
}
Traversal
Delete Duplicate Folders in System
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
private List<List<String>> ans = new ArrayList<>();
public List<List<String>> deleteDuplicateFolder(List<List<String>> paths) {
TrieNode root = new TrieNode();
paths.forEach(p -> buildTree(root, p));
deDupe(root);
root.children.values().forEach(this::dfs);
return ans;
}
class TrieNode {
String name = null;
// sorted map guarantees the serialization of identical subfolders is unique
Map<String, TrieNode> children = new TreeMap<>();
boolean toDelete = false;
public TrieNode() {
}
public TrieNode(String name) {
this.name = name;
}
}
private void buildTree(TrieNode root, List<String> path) {
for (String p : path) {
root.children.putIfAbsent(p, new TrieNode(p));
root = root.children.get(p);
}
}
// backtracking
List<String> path = new ArrayList<>();
private void dfs(TrieNode root) {
// skip deleted nodes
if (root.toDelete) {
return;
}
path.add(root.name);
ans.add(new ArrayList<>(path));
root.children.values().forEach(this::dfs);
path.remove(path.size() - 1);
}
// postorder
Map<String, TrieNode> seen = new HashMap<>();
private String deDupe(TrieNode root) {
String subfolders = "";
for (TrieNode child : root.children.values()) {
subfolders += deDupe(child);
}
if (!subfolders.isEmpty()) {
if (seen.containsKey(subfolders)) {
// if the subfolder has been seen before, marks the existing node as to-delete
seen.get(subfolders).toDelete = root.toDelete = true;
} else {
seen.put(subfolders, root);
}
}
// "()" ensures unique serialization
return "(" + root.name + subfolders + ")";
}
This post is licensed under CC BY 4.0 by the author.