diff --git a/README.md b/README.md index dc8d819..06d6f8b 100644 --- a/README.md +++ b/README.md @@ -285,7 +285,7 @@ Click on the icons to search by language - [ ] [path_sum](tree/binary_tree/path_sum) - [ ] [serialize_deserialize](tree/binary_tree/serialize_deserialize) - [ ] [traversal](tree/traversal) - - [ ] [inorder](tree/traversal/inorder) + - [x] [inorder](tree/traversal/inorder) - [ ] [level_order](tree/traversal/level_order) - [ ] [zigzag](tree/traversal/zigzag) - [ ] [binary_search_tree](tree/binary_search_tree) @@ -305,6 +305,8 @@ Click on the icons to search by language - [ ] [trie](tree/trie) - [ ] [add_and_search](tree/trie/add_and_search) - [ ] [trie](tree/trie/trie) + - [x] [new_tree_algorithm](tree/new_tree_algorithm) + - [x] [boundary_traversal](tree/new_tree_algorithm/new_tree_algorithm) - [x] [union-find](union-find) - [x] [count_islands](union-find/count_islands.py) diff --git a/tree/binary_tree/longest_consecutive_sequence/longest_consecutive_sequence.py b/tree/binary_tree/longest_consecutive_sequence/longest_consecutive_sequence.py index 8376fc2..789877c 100644 --- a/tree/binary_tree/longest_consecutive_sequence/longest_consecutive_sequence.py +++ b/tree/binary_tree/longest_consecutive_sequence/longest_consecutive_sequence.py @@ -1,6 +1,3 @@ -maxlen = 0 - - class Node: def __init__(self, val=None): self.left = None @@ -15,21 +12,22 @@ def longest_consecutive(root): """ if not root: return 0 - DFS(root, 0, root.val) - return maxlen + return DFS(root, None, 0) -def DFS(root, cur, target): - global maxlen +def DFS(root, parent, length): if not root: - return - if root.val == target: - cur += 1 + return length + + if parent and root.val == parent.val + 1: + length += 1 else: - cur = 1 - maxlen = max(cur, maxlen) - DFS(root.left, cur, root.val + 1) - DFS(root.right, cur, root.val + 1) + length = 1 + + left_length = DFS(root.left, root, length) + right_length = DFS(root.right, root, length) + + return max(length, left_length, right_length) if __name__ == '__main__': diff --git a/tree/binary_tree/longest_consecutive_sequence/test_longest_consecutive_sequence.py b/tree/binary_tree/longest_consecutive_sequence/test_longest_consecutive_sequence.py new file mode 100644 index 0000000..749d12d --- /dev/null +++ b/tree/binary_tree/longest_consecutive_sequence/test_longest_consecutive_sequence.py @@ -0,0 +1,36 @@ +import unittest +from longest_consecutive_sequence import Node, longest_consecutive + +class TestLongestConsecutiveSequence(unittest.TestCase): + def test_example_case(self): + root = Node(1) + root.right = Node(3) + root.right.left = Node(2) + root.right.right = Node(4) + root.right.right.right = Node(5) + self.assertEqual(longest_consecutive(root), 3) + + def test_empty_tree(self): + self.assertEqual(longest_consecutive(None), 0) + + def test_single_node(self): + root = Node(1) + self.assertEqual(longest_consecutive(root), 1) + + def test_no_consecutive_sequence(self): + root = Node(1) + root.left = Node(3) + root.right = Node(5) + self.assertEqual(longest_consecutive(root), 1) + + def test_multiple_consecutive_sequences(self): + root = Node(1) + root.left = Node(2) + root.left.left = Node(3) + root.right = Node(4) + root.right.right = Node(5) + root.right.right.right = Node(6) + self.assertEqual(longest_consecutive(root), 3) + +if __name__ == '__main__': + unittest.main() diff --git a/tree/binary_tree/novel_tree_algorithm.py b/tree/binary_tree/novel_tree_algorithm.py new file mode 100644 index 0000000..86e58fe --- /dev/null +++ b/tree/binary_tree/novel_tree_algorithm.py @@ -0,0 +1,61 @@ +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + +def find_deepest_leaf(root): + """ + Finds the deepest leaf node in a binary tree. + + :param root: TreeNode, the root of the binary tree + :return: tuple (TreeNode, int), the deepest leaf node and its depth + """ + if not root: + return None, 0 + + def dfs(node, depth): + if not node.left and not node.right: + return node, depth + + left_node, left_depth = dfs(node.left, depth + 1) if node.left else (None, depth) + right_node, right_depth = dfs(node.right, depth + 1) if node.right else (None, depth) + + if left_depth >= right_depth: + return left_node, left_depth + else: + return right_node, right_depth + + return dfs(root, 0) + +# Example usage and test +if __name__ == "__main__": + # Create a sample binary tree + root = TreeNode(1) + root.left = TreeNode(2) + root.right = TreeNode(3) + root.left.left = TreeNode(4) + root.right.right = TreeNode(5) + root.right.right.left = TreeNode(6) + + deepest_node, depth = find_deepest_leaf(root) + print(f"The deepest leaf node value is {deepest_node.val} at depth {depth}") + + # Additional test cases + # Test case 1: Empty tree + assert find_deepest_leaf(None) == (None, 0) + + # Test case 2: Tree with only root + assert find_deepest_leaf(TreeNode(1)) == (TreeNode(1), 0) + + # Test case 3: Balanced tree + balanced_root = TreeNode(1) + balanced_root.left = TreeNode(2) + balanced_root.right = TreeNode(3) + balanced_root.left.left = TreeNode(4) + balanced_root.left.right = TreeNode(5) + balanced_root.right.left = TreeNode(6) + balanced_root.right.right = TreeNode(7) + assert find_deepest_leaf(balanced_root)[1] == 2 + + print("All test cases passed!") diff --git a/tree/binary_tree/test_novel_tree_algorithm.py b/tree/binary_tree/test_novel_tree_algorithm.py new file mode 100644 index 0000000..02fd5ef --- /dev/null +++ b/tree/binary_tree/test_novel_tree_algorithm.py @@ -0,0 +1,56 @@ +import unittest +from .novel_tree_algorithm import TreeNode, find_deepest_leaf + +class TestNovelTreeAlgorithm(unittest.TestCase): + def test_empty_tree(self): + self.assertEqual(find_deepest_leaf(None), (None, 0)) + + def test_single_node_tree(self): + root = TreeNode(1) + node, depth = find_deepest_leaf(root) + self.assertEqual(node.val, 1) + self.assertEqual(depth, 0) + + def test_balanced_tree(self): + root = TreeNode(1) + root.left = TreeNode(2) + root.right = TreeNode(3) + root.left.left = TreeNode(4) + root.left.right = TreeNode(5) + root.right.left = TreeNode(6) + root.right.right = TreeNode(7) + node, depth = find_deepest_leaf(root) + self.assertIn(node.val, [4, 5, 6, 7]) + self.assertEqual(depth, 2) + + def test_unbalanced_tree(self): + root = TreeNode(1) + root.left = TreeNode(2) + root.right = TreeNode(3) + root.left.left = TreeNode(4) + root.right.right = TreeNode(5) + root.right.right.left = TreeNode(6) + node, depth = find_deepest_leaf(root) + self.assertEqual(node.val, 6) + self.assertEqual(depth, 3) + + def test_left_heavy_tree(self): + root = TreeNode(1) + root.left = TreeNode(2) + root.left.left = TreeNode(3) + root.left.left.left = TreeNode(4) + node, depth = find_deepest_leaf(root) + self.assertEqual(node.val, 4) + self.assertEqual(depth, 3) + + def test_right_heavy_tree(self): + root = TreeNode(1) + root.right = TreeNode(2) + root.right.right = TreeNode(3) + root.right.right.right = TreeNode(4) + node, depth = find_deepest_leaf(root) + self.assertEqual(node.val, 4) + self.assertEqual(depth, 3) + +if __name__ == '__main__': + unittest.main() diff --git a/tree/new_tree_algorithm.py b/tree/new_tree_algorithm.py new file mode 100644 index 0000000..62236da --- /dev/null +++ b/tree/new_tree_algorithm.py @@ -0,0 +1,71 @@ +class TreeNode: + def __init__(self, value): + self.value = value + self.left = None + self.right = None + +class BinaryTree: + def __init__(self): + self.root = None + + def insert(self, value): + if not self.root: + self.root = TreeNode(value) + else: + self._insert_recursive(self.root, value) + + def _insert_recursive(self, node, value): + if value < node.value: + if node.left is None: + node.left = TreeNode(value) + else: + self._insert_recursive(node.left, value) + else: + if node.right is None: + node.right = TreeNode(value) + else: + self._insert_recursive(node.right, value) + + def inorder_traversal(self): + result = [] + self._inorder_recursive(self.root, result) + return result + + def _inorder_recursive(self, node, result): + if node: + self._inorder_recursive(node.left, result) + result.append(node.value) + self._inorder_recursive(node.right, result) + + def preorder_traversal(self): + result = [] + self._preorder_recursive(self.root, result) + return result + + def _preorder_recursive(self, node, result): + if node: + result.append(node.value) + self._preorder_recursive(node.left, result) + self._preorder_recursive(node.right, result) + + def postorder_traversal(self): + result = [] + self._postorder_recursive(self.root, result) + return result + + def _postorder_recursive(self, node, result): + if node: + self._postorder_recursive(node.left, result) + self._postorder_recursive(node.right, result) + result.append(node.value) + +# Example usage +if __name__ == "__main__": + tree = BinaryTree() + values = [5, 3, 7, 1, 4, 6, 8] + for value in values: + tree.insert(value) + + print("Inorder traversal:", tree.inorder_traversal()) + print("Preorder traversal:", tree.preorder_traversal()) + print("Postorder traversal:", tree.postorder_traversal()) diff --git a/tree/new_tree_algorithm/new_tree_algorithm.py b/tree/new_tree_algorithm/new_tree_algorithm.py new file mode 100644 index 0000000..95ec0d7 --- /dev/null +++ b/tree/new_tree_algorithm/new_tree_algorithm.py @@ -0,0 +1,71 @@ +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + +def is_leaf(node): + return node and not node.left and not node.right + +def add_left_boundary(root, result): + current = root.left + while current: + if not is_leaf(current): + result.append(current.val) + if current.left: + current = current.left + else: + current = current.right + +def add_leaves(root, result): + if is_leaf(root): + result.append(root.val) + else: + if root.left: + add_leaves(root.left, result) + if root.right: + add_leaves(root.right, result) + +def add_right_boundary(root, result): + current = root.right + temp = [] + while current: + if not is_leaf(current): + temp.append(current.val) + if current.right: + current = current.right + else: + current = current.left + result.extend(temp[::-1]) + +def boundary_traversal(root): + result = [] + if not root: + return result + + if not is_leaf(root): + result.append(root.val) + + add_left_boundary(root, result) + add_leaves(root, result) + add_right_boundary(root, result) + + return result + +# Example usage +if __name__ == "__main__": + # Create a sample binary tree + root = TreeNode(1) + root.left = TreeNode(2) + root.right = TreeNode(3) + root.left.left = TreeNode(4) + root.left.right = TreeNode(5) + root.right.left = TreeNode(6) + root.right.right = TreeNode(7) + root.left.left.left = TreeNode(8) + root.left.left.right = TreeNode(9) + root.right.right.left = TreeNode(10) + root.right.right.right = TreeNode(11) + + # Perform boundary traversal + print("Boundary traversal:", boundary_traversal(root)) diff --git a/tree/trie/new_trie.py b/tree/trie/new_trie.py new file mode 100644 index 0000000..b4686ff --- /dev/null +++ b/tree/trie/new_trie.py @@ -0,0 +1,80 @@ +""" +Implement a new Trie data structure with insert, search, and starts_with methods. + +This implementation uses a TrieNode class to represent each node in the Trie. +Each TrieNode contains a dictionary of children nodes and a flag to indicate +if it represents the end of a word. + +Note: + - All inputs are assumed to consist of lowercase letters a-z. + - This implementation aims to be more memory-efficient by using a regular + dictionary instead of defaultdict for children nodes. +""" + + +class TrieNode: + def __init__(self): + self.children = {} + self.is_end_of_word = False + + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + + Args: + word (str): The word to be inserted. + """ + node = self.root + for char in word: + if char not in node.children: + node.children[char] = TrieNode() + node = node.children[char] + node.is_end_of_word = True + + def search(self, word: str) -> bool: + """ + Returns True if the word is in the trie, False otherwise. + + Args: + word (str): The word to search for. + + Returns: + bool: True if the word is found, False otherwise. + """ + node = self._find_node(word) + return node is not None and node.is_end_of_word + + def starts_with(self, prefix: str) -> bool: + """ + Returns True if there is any word in the trie that starts with the given prefix. + + Args: + prefix (str): The prefix to search for. + + Returns: + bool: True if any word starts with the given prefix, False otherwise. + """ + return self._find_node(prefix) is not None + + def _find_node(self, prefix: str) -> TrieNode: + """ + Helper method to find the node corresponding to the given prefix. + + Args: + prefix (str): The prefix to search for. + + Returns: + TrieNode: The node corresponding to the last character of the prefix, + or None if the prefix is not found. + """ + node = self.root + for char in prefix: + if char not in node.children: + return None + node = node.children[char] + return node diff --git a/tree/trie/test_new_trie.py b/tree/trie/test_new_trie.py new file mode 100644 index 0000000..ff4c9d2 --- /dev/null +++ b/tree/trie/test_new_trie.py @@ -0,0 +1,38 @@ +import unittest +from new_trie import Trie + +class TestTrie(unittest.TestCase): + def setUp(self): + self.trie = Trie() + + def test_insert_and_search(self): + self.trie.insert("apple") + self.assertTrue(self.trie.search("apple")) + self.assertFalse(self.trie.search("app")) + self.assertFalse(self.trie.search("apples")) + + def test_starts_with(self): + self.trie.insert("apple") + self.assertTrue(self.trie.starts_with("app")) + self.assertTrue(self.trie.starts_with("apple")) + self.assertFalse(self.trie.starts_with("apq")) + + def test_multiple_words(self): + words = ["apple", "app", "apricot", "banana", "bat"] + for word in words: + self.trie.insert(word) + + for word in words: + self.assertTrue(self.trie.search(word)) + + self.assertTrue(self.trie.starts_with("ap")) + self.assertTrue(self.trie.starts_with("ba")) + self.assertFalse(self.trie.starts_with("c")) + + def test_empty_string(self): + self.trie.insert("") + self.assertTrue(self.trie.search("")) + self.assertTrue(self.trie.starts_with("")) + +if __name__ == "__main__": + unittest.main()