From 8e5d4ea7529ae4f93e56af76e456daac1ed0a30e Mon Sep 17 00:00:00 2001 From: Ivsucram Date: Sun, 13 Apr 2025 20:03:59 +0800 Subject: [PATCH] Tutorial 6 - 13 April 2025 --- T6/Answer/Q1 - count_words.py | 85 +++++++++++++ T6/Answer/Q2 - find_words_with_prefix.py | 98 +++++++++++++++ .../Q3 - find_shortest_word_with_prefix.py | 112 ++++++++++++++++++ T6/Base/Q1 - count_words.py | 75 ++++++++++++ T6/Base/Q2 - find_words_with_prefix.py | 83 +++++++++++++ .../Q3 - find_shortest_word_with_prefix.py | 80 +++++++++++++ 6 files changed, 533 insertions(+) create mode 100644 T6/Answer/Q1 - count_words.py create mode 100644 T6/Answer/Q2 - find_words_with_prefix.py create mode 100644 T6/Answer/Q3 - find_shortest_word_with_prefix.py create mode 100644 T6/Base/Q1 - count_words.py create mode 100644 T6/Base/Q2 - find_words_with_prefix.py create mode 100644 T6/Base/Q3 - find_shortest_word_with_prefix.py diff --git a/T6/Answer/Q1 - count_words.py b/T6/Answer/Q1 - count_words.py new file mode 100644 index 0000000..26aef07 --- /dev/null +++ b/T6/Answer/Q1 - count_words.py @@ -0,0 +1,85 @@ +class TrieNode: + def __init__(self, char=None): + self.char = char + self.first_child = None + self.next_sibling = None + self.is_end_of_word = False + +class Queue: + def __init__(self): + self.items = [] + + def enqueue(self, item): + self.items.append(item) # Add to the end + + def dequeue(self): + if not self.is_empty(): + return self.items.pop(0) # Remove from the front + return None + + def is_empty(self): + return len(self.items) == 0 + + def size(self): + return len(self.items) + +def _find_child(node, char): + current = node.first_child + while current: + if current.char == char: + return current + current = current.next_sibling + return None + + +def _add_child(node, char): + new_node = TrieNode(char) + new_node.next_sibling = node.first_child + node.first_child = new_node + return new_node + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert(self, word): + node = self.root + for char in word: + child = _find_child(node, char) + if not child: + child = _add_child(node, char) + node = child + node.is_end_of_word = True + + def search(self, word): + node = self.root + for char in word: + node = _find_child(node, char) + if not node: + return False + return node.is_end_of_word + + def count_words(self, node): #question 1 + if node.is_end_of_word: + cnt = 1 + else: + cnt = 0 + + child = node.first_child + while child: + cnt += self.count_words(child) + child = child.next_sibling + return cnt + +trie = Trie() +trie.insert("cat") +trie.insert("car") +trie.insert("care") +trie.insert("cane") +trie.insert("camera") +trie.insert("campus") +trie.insert("camp") +trie.insert("dog") +trie.insert("dot") + +print("Total words in Trie:", trie.count_words(trie.root)) \ No newline at end of file diff --git a/T6/Answer/Q2 - find_words_with_prefix.py b/T6/Answer/Q2 - find_words_with_prefix.py new file mode 100644 index 0000000..887ea89 --- /dev/null +++ b/T6/Answer/Q2 - find_words_with_prefix.py @@ -0,0 +1,98 @@ +class TrieNode: + def __init__(self, char=None): + self.char = char + self.first_child = None + self.next_sibling = None + self.is_end_of_word = False + +class Queue: + def __init__(self): + self.items = [] + + def enqueue(self, item): + self.items.append(item) # Add to the end + + def dequeue(self): + if not self.is_empty(): + return self.items.pop(0) # Remove from the front + return None + + def is_empty(self): + return len(self.items) == 0 + + def size(self): + return len(self.items) + +def _find_child(node, char): + current = node.first_child + while current: + if current.char == char: + return current + current = current.next_sibling + return None + +def _add_child(node, char): + new_node = TrieNode(char) + new_node.next_sibling = node.first_child + node.first_child = new_node + return new_node + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert(self, word): + node = self.root + for char in word: + child = _find_child(node, char) + if not child: + child = _add_child(node, char) + node = child + node.is_end_of_word = True + + def search(self, word): + node = self.root + for char in word: + node = _find_child(node, char) + if not node: + return False + return node.is_end_of_word + + def collect_all_words(self, node, prefix, results): + if node.is_end_of_word: + results.append(prefix) + + child = node.first_child + while child: + self.collect_all_words(child, prefix + child.char, results) + child = child.next_sibling + + def find_words_with_prefix(self, prefix): #question 2 + results = [] + node = self.root + + for char in prefix: + node = _find_child(node, char) + if not node: + return [] + + self.collect_all_words(node, prefix, results) + return results + +trie = Trie() +trie.insert("cat") +trie.insert("car") +trie.insert("care") +trie.insert("cane") +trie.insert("camera") +trie.insert("campus") +trie.insert("camp") +trie.insert("dog") +trie.insert("dot") + +prefix1 = "ca" +prefix2 = "do" +prefix3 = "z" +print(f"Words starting with '{prefix1}': ", trie.find_words_with_prefix(prefix1)) +print(f"Words starting with '{prefix2}':", trie.find_words_with_prefix(prefix2)) +print(f"Words starting with '{prefix3}':", trie.find_words_with_prefix(prefix3)) \ No newline at end of file diff --git a/T6/Answer/Q3 - find_shortest_word_with_prefix.py b/T6/Answer/Q3 - find_shortest_word_with_prefix.py new file mode 100644 index 0000000..5aa47b3 --- /dev/null +++ b/T6/Answer/Q3 - find_shortest_word_with_prefix.py @@ -0,0 +1,112 @@ +class TrieNode: + def __init__(self, char=None): + self.char = char + self.first_child = None + self.next_sibling = None + self.is_end_of_word = False + +class Queue: + def __init__(self): + self.items = [] + + def enqueue(self, item): + self.items.append(item) # Add to the end + + def dequeue(self): + if not self.is_empty(): + return self.items.pop(0) # Remove from the front + return None + + def is_empty(self): + return len(self.items) == 0 + + def size(self): + return len(self.items) + +def _find_child(node, char): + current = node.first_child + while current: + if current.char == char: + return current + current = current.next_sibling + return None + +def _add_child(node, char): + new_node = TrieNode(char) + new_node.next_sibling = node.first_child + node.first_child = new_node + return new_node + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert(self, word): + node = self.root + for char in word: + child = _find_child(node, char) + if not child: + child = _add_child(node, char) + node = child + node.is_end_of_word = True + + def search(self, word): + node = self.root + for char in word: + node = _find_child(node, char) + if not node: + return False + return node.is_end_of_word + + def find_shortest_word_with_prefix(self, prefix):#question 3 + # Step 1: Traverse to the end of the prefix + node = self.root + for char in prefix: + node = _find_child(node, char) + if not node: + return None # Prefix not found + + # Step 2: BFS + queue = Queue() + queue.enqueue((node, prefix, 0)) # (node, word, depth) + shortest_words = [] + min_depth = None + + while not queue.is_empty(): + node, word, depth = queue.dequeue() + + if node.is_end_of_word: + if min_depth is None: + min_depth = depth + if depth == min_depth: + shortest_words.append(word) + elif depth > min_depth: + break # We already found the shortest level, skip deeper + + if min_depth is not None and depth >= min_depth: + continue # don't enqueue deeper nodes + + child = node.first_child + while child: + queue.enqueue((child, word + child.char, depth + 1)) + child = child.next_sibling + + return shortest_words + +trie = Trie() +trie.insert("cat") +trie.insert("car") +trie.insert("care") +trie.insert("cane") +trie.insert("camera") +trie.insert("campus") +trie.insert("camp") +trie.insert("dog") +trie.insert("dot") + +prefix1 = "ca" +prefix2 = "do" +prefix3 = "z" +print(f"Shortest word starting with '{prefix1}':", trie.find_shortest_word_with_prefix(prefix1)) +print(f"Shortest word starting with '{prefix2}':", trie.find_shortest_word_with_prefix(prefix2)) +print(f"Shortest word starting with '{prefix3}':", trie.find_shortest_word_with_prefix(prefix3)) diff --git a/T6/Base/Q1 - count_words.py b/T6/Base/Q1 - count_words.py new file mode 100644 index 0000000..a379052 --- /dev/null +++ b/T6/Base/Q1 - count_words.py @@ -0,0 +1,75 @@ +class TrieNode: + def __init__(self, char=None): + self.char = char + self.first_child = None + self.next_sibling = None + self.is_end_of_word = False + +class Queue: + def __init__(self): + self.items = [] + + def enqueue(self, item): + self.items.append(item) # Add to the end + + def dequeue(self): + if not self.is_empty(): + return self.items.pop(0) # Remove from the front + return None + + def is_empty(self): + return len(self.items) == 0 + + def size(self): + return len(self.items) + +def _find_child(node, char): + current = node.first_child + while current: + if current.char == char: + return current + current = current.next_sibling + return None + +def _add_child(node, char): + new_node = TrieNode(char) + new_node.next_sibling = node.first_child + node.first_child = new_node + return new_node + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert(self, word): + node = self.root + for char in word: + child = _find_child(node, char) + if not child: + child = _add_child(node, char) + node = child + node.is_end_of_word = True + + def search(self, word): + node = self.root + for char in word: + node = _find_child(node, char) + if not node: + return False + return node.is_end_of_word + + def count_words(self, node): #question 1 + raise NotImplementedError + +trie = Trie() +trie.insert("cat") +trie.insert("car") +trie.insert("care") +trie.insert("cane") +trie.insert("camera") +trie.insert("campus") +trie.insert("camp") +trie.insert("dog") +trie.insert("dot") + +print("Total words in Trie:", trie.count_words(trie.root)) \ No newline at end of file diff --git a/T6/Base/Q2 - find_words_with_prefix.py b/T6/Base/Q2 - find_words_with_prefix.py new file mode 100644 index 0000000..41bac45 --- /dev/null +++ b/T6/Base/Q2 - find_words_with_prefix.py @@ -0,0 +1,83 @@ +class TrieNode: + def __init__(self, char=None): + self.char = char + self.first_child = None + self.next_sibling = None + self.is_end_of_word = False + +class Queue: + def __init__(self): + self.items = [] + + def enqueue(self, item): + self.items.append(item) # Add to the end + + def dequeue(self): + if not self.is_empty(): + return self.items.pop(0) # Remove from the front + return None + + def is_empty(self): + return len(self.items) == 0 + + def size(self): + return len(self.items) + +def _find_child(node, char): + current = node.first_child + while current: + if current.char == char: + return current + current = current.next_sibling + return None + +def _add_child(node, char): + new_node = TrieNode(char) + new_node.next_sibling = node.first_child + node.first_child = new_node + return new_node + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert(self, word): + node = self.root + for char in word: + child = _find_child(node, char) + if not child: + child = _add_child(node, char) + node = child + node.is_end_of_word = True + + def search(self, word): + node = self.root + for char in word: + node = _find_child(node, char) + if not node: + return False + return node.is_end_of_word + + def collect_all_words(self, node, prefix, results): + raise NotImplementedError + + def find_words_with_prefix(self, prefix): #question 2 + raise NotImplementedError + +trie = Trie() +trie.insert("cat") +trie.insert("car") +trie.insert("care") +trie.insert("cane") +trie.insert("camera") +trie.insert("campus") +trie.insert("camp") +trie.insert("dog") +trie.insert("dot") + +prefix1 = "ca" +prefix2 = "do" +prefix3 = "z" +print(f"Words starting with '{prefix1}': ", trie.find_words_with_prefix(prefix1)) +print(f"Words starting with '{prefix2}':", trie.find_words_with_prefix(prefix2)) +print(f"Words starting with '{prefix3}':", trie.find_words_with_prefix(prefix3)) \ No newline at end of file diff --git a/T6/Base/Q3 - find_shortest_word_with_prefix.py b/T6/Base/Q3 - find_shortest_word_with_prefix.py new file mode 100644 index 0000000..863b375 --- /dev/null +++ b/T6/Base/Q3 - find_shortest_word_with_prefix.py @@ -0,0 +1,80 @@ +class TrieNode: + def __init__(self, char=None): + self.char = char + self.first_child = None + self.next_sibling = None + self.is_end_of_word = False + +class Queue: + def __init__(self): + self.items = [] + + def enqueue(self, item): + self.items.append(item) # Add to the end + + def dequeue(self): + if not self.is_empty(): + return self.items.pop(0) # Remove from the front + return None + + def is_empty(self): + return len(self.items) == 0 + + def size(self): + return len(self.items) + +def _find_child(node, char): + current = node.first_child + while current: + if current.char == char: + return current + current = current.next_sibling + return None + +def _add_child(node, char): + new_node = TrieNode(char) + new_node.next_sibling = node.first_child + node.first_child = new_node + return new_node + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert(self, word): + node = self.root + for char in word: + child = _find_child(node, char) + if not child: + child = _add_child(node, char) + node = child + node.is_end_of_word = True + + def search(self, word): + node = self.root + for char in word: + node = _find_child(node, char) + if not node: + return False + return node.is_end_of_word + + def find_shortest_word_with_prefix(self, prefix):#question 3 + raise NotImplementedError + +trie = Trie() +trie.insert("cat") +trie.insert("car") +trie.insert("care") +trie.insert("cane") +trie.insert("camera") +trie.insert("campus") +trie.insert("camp") +trie.insert("dog") +trie.insert("dot") + +prefix1 = "ca" +prefix2 = "do" +prefix3 = "z" +print(f"Shortest word starting with '{prefix1}':", trie.find_shortest_word_with_prefix(prefix1)) +print(f"Shortest word starting with '{prefix2}':", trie.find_shortest_word_with_prefix(prefix2)) +print(f"Shortest word starting with '{prefix3}':", trie.find_shortest_word_with_prefix(prefix3))