diff --git a/hw01/sp/Trie.java b/hw01/sp/Trie.java
new file mode 100644
index 0000000..4ebfd31
--- /dev/null
+++ b/hw01/sp/Trie.java
@@ -0,0 +1,32 @@
+package sp;
+
+public interface Trie {
+
+ /**
+ * Expected complexity: O(|element|)
+ * @return true if this set did not already contain the specified
+ * element
+ */
+ boolean add(String element);
+
+ /**
+ * Expected complexity: O(|element|)
+ */
+ boolean contains(String element);
+
+ /**
+ * Expected complexity: O(|element|)
+ * @return true if this set contained the specified element
+ */
+ boolean remove(String element);
+
+ /**
+ * Expected complexity: O(1)
+ */
+ int size();
+
+ /**
+ * Expected complexity: O(|prefix|)
+ */
+ int howManyStartsWithPrefix(String prefix);
+}
\ No newline at end of file
diff --git a/hw01/sp/TrieImpl.java b/hw01/sp/TrieImpl.java
new file mode 100644
index 0000000..975b358
--- /dev/null
+++ b/hw01/sp/TrieImpl.java
@@ -0,0 +1,96 @@
+package sp;
+
+import java.lang.Character;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.TreeSet;
+import java.util.Map;
+
+public class TrieImpl implements Trie {
+
+ Node root = new Node();
+
+ public boolean add(String element) {
+ Node node = root;
+ for(char c : element.toCharArray())
+ node = node.next(c);
+ return node.setLeaf(true);
+ }
+
+ public boolean contains(String element) {
+ Node node = root;
+ for(char c : element.toCharArray()) {
+ if (!node.containsKey(c))
+ return false;
+ node = node.get(c);
+ }
+ return node.isLeaf();
+ }
+
+ public boolean remove(String element) {
+ Node node = root;
+ for(char c : element.toCharArray()) {
+ if (!node.containsKey(c))
+ return false;
+ node = node.get(c);
+ }
+ return node.setLeaf(false);
+ }
+
+ public int size() {
+ return root.getSize();
+ }
+
+ public int howManyStartsWithPrefix(String prefix) {
+ Node node = root;
+ for(char c : prefix.toCharArray()) {
+ if (!node.containsKey(c))
+ return 0;
+ node = node.get(c);
+ }
+ return node.getSize();
+ }
+
+ private class Node extends HashMap {
+
+ private int wordCount = 0;
+ private boolean isLeaf = false;
+ private WeakReference parrent = null;
+ private Character character = null;
+
+ public Node() {}
+
+ public Node(Node prev, Character c) {
+ parrent = new WeakReference<>(prev);
+ character = c;
+ }
+
+ public Node next(Character key) {
+ if (!containsKey(key))
+ put(key, new Node(this, key));
+ return get(key);
+ }
+
+ public int getSize() { return wordCount; }
+
+ private void updateSize(Character c, int delta) {
+ if (c != null && get(c).getSize() == 0) {
+ remove(c);
+ }
+ wordCount += delta;
+ if (parrent != null)
+ parrent.get().updateSize(this.character, delta);
+ }
+
+ boolean isLeaf() { return isLeaf; }
+
+ boolean setLeaf(boolean value) {
+ if (isLeaf == value)
+ return false;
+ isLeaf = value;
+ updateSize(null, value ? 1 : -1);
+ return true;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/hw01/sp/TrieTest.java b/hw01/sp/TrieTest.java
new file mode 100644
index 0000000..d0012dd
--- /dev/null
+++ b/hw01/sp/TrieTest.java
@@ -0,0 +1,197 @@
+package sp;
+
+import static org.junit.Assert.*;
+
+public class TrieTest {
+
+ @org.junit.Test
+ public void testAdd() throws Exception {
+ Trie trie = new TrieImpl();
+
+ assertTrue(trie.add(""));
+ assertTrue(trie.add("aa"));
+ assertTrue(trie.add("a"));
+ assertTrue(trie.add("aaa"));
+ assertTrue(trie.add("aab"));
+ assertTrue(trie.add("aac"));
+ assertTrue(trie.add("ab"));
+
+ assertFalse(trie.add(""));
+ assertFalse(trie.add("aa"));
+ assertFalse(trie.add("a"));
+ assertFalse(trie.add("aaa"));
+ assertFalse(trie.add("aab"));
+ assertFalse(trie.add("aac"));
+ assertFalse(trie.add("ab"));
+
+ trie.remove("");
+ trie.remove("aab");
+
+ assertTrue(trie.add("aaaa"));
+ assertFalse(trie.add("aaaa"));
+
+ trie.remove("a");
+ trie.remove("aa");
+ trie.remove("aaa");
+ trie.remove("aac");
+ trie.remove("ab");
+ }
+
+ @org.junit.Test
+ public void testRemove() throws Exception {
+ Trie trie = new TrieImpl();
+ assertFalse(trie.contains(""));
+ trie.add("");
+ trie.add("aa");
+ trie.add("a");
+ trie.add("aaa");
+ trie.add("aab");
+ trie.add("aac");
+ trie.add("ab");
+ assertTrue(trie.remove(""));
+ assertTrue(trie.remove("aab"));
+ trie.add("aaaa");
+ assertTrue(trie.remove("a"));
+ assertTrue(trie.remove("aa"));
+ assertTrue(trie.remove("aaa"));
+ assertTrue(trie.remove("aac"));
+ assertTrue(trie.remove("ab"));
+
+ assertFalse(trie.remove(""));
+ assertFalse(trie.remove("aab"));
+ assertFalse(trie.remove(""));
+ assertFalse(trie.remove("aab"));
+ assertFalse(trie.remove("a"));
+ assertFalse(trie.remove("aa"));
+ assertFalse(trie.remove("aaa"));
+ assertFalse(trie.remove("aac"));
+ assertFalse(trie.remove("ab"));
+ }
+
+ @org.junit.Test
+ public void testContains() throws Exception {
+ Trie trie = new TrieImpl();
+ assertFalse(trie.contains(""));
+ trie.add("");
+ trie.add("aa");
+ trie.add("a");
+ trie.add("aaa");
+ trie.add("aab");
+ trie.add("aac");
+ trie.add("ab");
+
+ assertTrue(trie.contains(""));
+ assertTrue(trie.contains("aa"));
+ assertTrue(trie.contains("a"));
+ assertTrue(trie.contains("aaa"));
+ assertTrue(trie.contains("aab"));
+ assertTrue(trie.contains("aac"));
+ assertTrue(trie.contains("ab"));
+
+ trie.remove("");
+ trie.remove("aab");
+
+ assertFalse(trie.contains(""));
+ assertTrue(trie.contains("aa"));
+ assertTrue(trie.contains("a"));
+ assertTrue(trie.contains("aaa"));
+ assertFalse(trie.contains("aab"));
+ assertTrue(trie.contains("aac"));
+ assertTrue(trie.contains("ab"));
+
+ trie.add("aaaa");
+ trie.remove("a");
+ trie.remove("aa");
+ trie.remove("aaa");
+ trie.remove("aac");
+ trie.remove("ab");
+
+ assertFalse(trie.contains(""));
+ assertFalse(trie.contains("aa"));
+ assertFalse(trie.contains("a"));
+ assertFalse(trie.contains("aaa"));
+ assertFalse(trie.contains("aab"));
+ assertFalse(trie.contains("aac"));
+ assertFalse(trie.contains("ab"));
+ assertTrue(trie.contains("aaaa"));
+ }
+
+ @org.junit.Test
+ public void testSize() throws Exception {
+ Trie trie = new TrieImpl();
+
+ assertEquals(trie.size(), 0);
+ trie.add("");
+ assertEquals(trie.size(), 1);
+ trie.add("aa");
+ trie.add("a");
+ trie.add("aaa");
+ assertEquals(trie.size(), 4);
+ trie.add("aab");
+ trie.add("aac");
+ trie.add("ab");
+ assertEquals(trie.size(), 7);
+
+ trie.remove("");
+ trie.remove("aab");
+ assertEquals(trie.size(), 5);
+
+ trie.add("aaaa");
+ assertEquals(trie.size(), 6);
+
+ trie.remove("a");
+ trie.remove("aa");
+ trie.remove("aaa");
+ assertEquals(trie.size(), 3);
+ trie.remove("aac");
+ trie.remove("ab");
+ assertEquals(trie.size(), 1);
+
+ }
+
+ @org.junit.Test
+ public void testHowManyStartsWithPrefix() throws Exception {
+ Trie trie = new TrieImpl();
+
+ assertEquals(trie.howManyStartsWithPrefix(""), 0);
+ assertEquals(trie.howManyStartsWithPrefix("a"), 0);
+ assertEquals(trie.howManyStartsWithPrefix("aa"), 0);
+ assertEquals(trie.howManyStartsWithPrefix("aaa"), 0);
+
+ trie.add("");
+ trie.add("aa");
+ trie.add("a");
+ trie.add("aaa");
+ trie.add("aab");
+ trie.add("aac");
+ trie.add("ab");
+
+ assertEquals(trie.howManyStartsWithPrefix(""), 7);
+ assertEquals(trie.howManyStartsWithPrefix("a"), 6);
+ assertEquals(trie.howManyStartsWithPrefix("aa"), 4);
+ assertEquals(trie.howManyStartsWithPrefix("aaa"), 1);
+
+ trie.remove("");
+ trie.remove("aab");
+
+ trie.add("aaaa");
+
+ assertEquals(trie.howManyStartsWithPrefix(""), 6);
+ assertEquals(trie.howManyStartsWithPrefix("a"), 6);
+ assertEquals(trie.howManyStartsWithPrefix("aa"), 4);
+ assertEquals(trie.howManyStartsWithPrefix("aaa"), 2);
+
+ trie.remove("a");
+ trie.remove("aa");
+ trie.remove("aaa");
+ trie.remove("aac");
+ trie.remove("ab");
+
+ assertEquals(trie.howManyStartsWithPrefix(""), 1);
+ assertEquals(trie.howManyStartsWithPrefix("a"), 1);
+ assertEquals(trie.howManyStartsWithPrefix("aa"), 1);
+ assertEquals(trie.howManyStartsWithPrefix("aaa"), 1);
+ }
+
+
+}
\ No newline at end of file