-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprefix_tree.java
More file actions
146 lines (121 loc) · 3.95 KB
/
prefix_tree.java
File metadata and controls
146 lines (121 loc) · 3.95 KB
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
Prefix Tree (Trie) implementation for efficient string prefix operations.
Supports:
- insert(word): Add a word to the trie - O(m) where m is word length
- search(word): Check if exact word exists - O(m)
- startsWith(prefix): Check if any word starts with prefix - O(m)
- delete(word): Remove a word from the trie - O(m)
Space complexity: O(ALPHABET_SIZE * N * M) where N is number of words and M is average length
*/
import java.util.*;
class prefix_tree {
static class TrieNode {
Map<Character, TrieNode> children;
boolean isEndOfWord;
TrieNode() {
children = new HashMap<>();
isEndOfWord = false;
}
}
static class PrefixTree {
private TrieNode root;
PrefixTree() {
root = new TrieNode();
}
void insert(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
node.children.putIfAbsent(c, new TrieNode());
node = node.children.get(c);
}
node.isEndOfWord = true;
}
boolean search(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
if (!node.children.containsKey(c)) {
return false;
}
node = node.children.get(c);
}
return node.isEndOfWord;
}
boolean startsWith(String prefix) {
TrieNode node = root;
for (char c : prefix.toCharArray()) {
if (!node.children.containsKey(c)) {
return false;
}
node = node.children.get(c);
}
return true;
}
boolean delete(String word) {
return deleteHelper(root, word, 0);
}
private boolean deleteHelper(TrieNode node, String word, int depth) {
if (node == null) {
return false;
}
if (depth == word.length()) {
if (!node.isEndOfWord) {
return false;
}
node.isEndOfWord = false;
return node.children.isEmpty();
}
char c = word.charAt(depth);
if (!node.children.containsKey(c)) {
return false;
}
TrieNode child = node.children.get(c);
boolean shouldDeleteChild = deleteHelper(child, word, depth + 1);
if (shouldDeleteChild) {
node.children.remove(c);
return !node.isEndOfWord && node.children.isEmpty();
}
return false;
}
}
static void testMain() {
PrefixTree trie = new PrefixTree();
trie.insert("cat");
trie.insert("car");
trie.insert("card");
assert trie.search("car");
assert !trie.search("ca");
assert trie.startsWith("car");
}
// Don't write tests below during competition.
static void testEmpty() {
PrefixTree trie = new PrefixTree();
assert !trie.search("test");
assert !trie.startsWith("test");
}
static void testOverlappingWords() {
PrefixTree trie = new PrefixTree();
trie.insert("car");
trie.insert("card");
trie.insert("care");
trie.insert("careful");
assert trie.search("car");
assert trie.search("card");
assert trie.search("careful");
assert !trie.search("ca");
assert trie.startsWith("car");
assert trie.startsWith("care");
}
static void testDeleteNonexistent() {
PrefixTree trie = new PrefixTree();
trie.insert("test");
assert !trie.delete("testing");
assert trie.search("test");
}
public static void main(String[] args) {
testEmpty();
testOverlappingWords();
testDeleteNonexistent();
testMain();
System.out.println("All tests passed!");
}
}