From db234786fd33e4058df457fcb11673c721208b51 Mon Sep 17 00:00:00 2001 From: Ryan Maleki Date: Sat, 15 Mar 2025 19:32:19 -0700 Subject: [PATCH] Add examples and clarification for tree problems, add diagram to tree readme --- queue/symmetrical_binary_tree_test.go | 2 +- tree/README.md | 8 ++++---- tree/autocompletion_test.go | 9 ++++++--- tree/evaluate_expression_test.go | 13 +++++++++++-- tree/reverse_binary_tree_test.go | 9 ++++++--- tree/serialize_tree.go | 4 ++-- tree/serialize_tree_test.go | 17 +++++++++++++---- tree/sorted_array_to_balanced_bsd_test.go | 16 +++++++++++++++- tree/traverse_binary_tree_test.go | 11 ++++++++--- 9 files changed, 66 insertions(+), 23 deletions(-) diff --git a/queue/symmetrical_binary_tree_test.go b/queue/symmetrical_binary_tree_test.go index 64555b5..bfe4554 100644 --- a/queue/symmetrical_binary_tree_test.go +++ b/queue/symmetrical_binary_tree_test.go @@ -42,7 +42,7 @@ func TestIsTreeSymmetrical(t *testing.T) { {"2,4,4,5,6,6,5", true}, } for i, test := range tests { - got, err := IsTreeSymmetrical(tree.Unserialize(test.tree)) + got, err := IsTreeSymmetrical(tree.Deserialize(test.tree)) if err != nil { t.Fatalf("Failed test case #%d. Unexpected error %s", i, err) } diff --git a/tree/README.md b/tree/README.md index 0cf5a72..0c43d5d 100644 --- a/tree/README.md +++ b/tree/README.md @@ -15,7 +15,7 @@ Traversing a tree means exploring every node in a tree and performing some work 1 3 5 7 ``` -Tree traversal methods are named after the order in which the nodes are explored. For example, in Pre-Order traversal, the node is explored before its children; in Post-Order traversal, the node is explored after its children. +Tree traversal methods are named after the order in which the nodes are explored. For example, in Pre-Order traversal, the node is explored before its children; in Post-Order traversal, the node is explored after its children. Children are always traversed from left to right. There are many types of trees. Some important tree types include: @@ -29,7 +29,7 @@ There are many types of trees. Some important tree types include: 1 4 1 * 1 - Is it a binary tree? /|\ / \ / / \ 2 - Is it a complete binary tree? / | \ / \ 2 / \ 3 - Is it a full binary tree? - 2 5 6 2 6 / \ * + + 2 5 6 2 6 / \ * + 1 2 3 / \ / \ \ / 3 4 / \ / \ A 0 0 0 3 4 7 8 3 5 5 5 2 2 B 1 0 0 C 1 1 0 @@ -48,7 +48,7 @@ The time complexity of operations such as Search, Deletion, Insertion, and findi ## AVL - Height Balanced BST -A height-balanced binary search tree has a height of O(Log n), and its left and right subtrees of all nodes have equal heights. +An AVL tree is a height-balanced binary search tree has a height of O(Log n), and its left and right subtrees of all nodes have equal heights. AVL stands for the name of the people who came up with the idea. To maintain balance after an insertion, a single rotation is needed if the insertion is on the outer side, either left-left or right-right, while a double rotation is required if the insertion is on the inner side, either left-right or right-left. @@ -66,7 +66,7 @@ Insertion and Search are done in O(K), where K is the length word length. ## Application -Trees, such as Binary Search Trees (BSTs), offer O(Log n) time complexity for searches, which is superior to [linked lists](../linkedlist/)' and [array](../array/)'s linear access time. Trees are widely employed in search systems, and operating systems can represent file information using tree structures. +Trees, such as Binary Search Trees (BSTs), offer O(Log n) time complexity for searches, which is superior to [linked lists](../linkedlist/)' and [array](../array/)'s linear access time. Trees are widely employed in search systems. Operating systems can represent file information using tree structures. ## Rehearsal diff --git a/tree/autocompletion_test.go b/tree/autocompletion_test.go index eb5bd72..8d89efe 100644 --- a/tree/autocompletion_test.go +++ b/tree/autocompletion_test.go @@ -10,9 +10,11 @@ TestAutocompletion tests solution(s) with the following signature and problem de func (t *trie) AutoComplete(word string) []string -Given a word like "car" and a dictionary like {"car","caravan","card","carpet","cap","ca"}, -return autocomplete suggestions where the given word is the prefix of a dictionary word -like {"avan","d","pet"}. +Given a dictionary of words and a word, return autocomplete suggestions from the dictionary that +start with the given word. + +For example given {"car","caravan","card","carpet","cap","ca"}, and the word "car", return +{"avan","d","pet"} because they are all words that start with "car". */ func TestAutocompletion(t *testing.T) { tests := []struct { @@ -32,6 +34,7 @@ func TestAutocompletion(t *testing.T) { {"ab", []string{"abc", "abcc", "abccd", "abd", "abe"}, []string{"c", "cc", "ccd", "d", "e"}}, {"ab", []string{"abc", "abcc", "abcd", "abd", "abe"}, []string{"c", "cc", "cd", "d", "e"}}, {"ab", []string{"abc", "abcd", "abd", "abcc", "abe"}, []string{"c", "cc", "cd", "d", "e"}}, + {"car", []string{"car", "caravan", "card", "carpet", "cap", "ca"}, []string{"avan", "d", "pet"}}, } for i, test := range tests { diff --git a/tree/evaluate_expression_test.go b/tree/evaluate_expression_test.go index 8cf6569..f66c5ff 100644 --- a/tree/evaluate_expression_test.go +++ b/tree/evaluate_expression_test.go @@ -10,8 +10,17 @@ TestEvaluateBinaryExpressionTree tests solution(s) with the following signature func EvaluateBinaryExpressionTree(node *stringBinaryTreeNode) (float64, error) -Given an expression binary tree like (D) in _Figure2_ evaluate it to a float64 like 100 allowing four -arithmetic operations. +Given an expression binary tree that contains integers and the four basic arithmetic operations, return +the resulting evaluation of the expression. + + * + / \ + / \ + * + + / \ / \ + 5 5 2 2 + +For example given "*,*,+,5,5,2,2" representing the above tree return 100 because (5 * 5) * (2 + 2) = 100. */ func TestEvaluateBinaryExpressionTree(t *testing.T) { tests := []struct { diff --git a/tree/reverse_binary_tree_test.go b/tree/reverse_binary_tree_test.go index 95a2db8..1caa723 100644 --- a/tree/reverse_binary_tree_test.go +++ b/tree/reverse_binary_tree_test.go @@ -5,8 +5,9 @@ import "testing" /* TestReverseBinaryTree tests solution(s) with the following signature and problem description: - func ReverseBinaryTree(root *BinaryTreeNode) *BinaryTreeNode + func ReverseBinaryTree(root *BinaryTreeNode) *BinaryTreeNode +Given a binary tree, reverse it. 1 / \ @@ -14,13 +15,15 @@ TestReverseBinaryTree tests solution(s) with the following signature and problem / \ / \ 4 5 6 7 -Reverse a binary search tree, the above tree should become: +For example given the above tree, return: 1 / \ 3 2 / \ / \ 7 6 5 4 + +Each tree is represented as a string by "1,2,3,4,5,6,7" and "1,3,2,7,6,5,4" respectively. */ func TestReverseBinaryTree(t *testing.T) { tests := []struct { @@ -34,7 +37,7 @@ func TestReverseBinaryTree(t *testing.T) { } for i, test := range tests { - if got := Serialize(ReverseBinaryTree(Unserialize(test.tree))); got != test.reversed { + if got := Serialize(ReverseBinaryTree(Deserialize(test.tree))); got != test.reversed { t.Fatalf("Failed test case #%d. Want %s got %s", i, test.reversed, got) } } diff --git a/tree/serialize_tree.go b/tree/serialize_tree.go index ff72e2c..3fae74e 100644 --- a/tree/serialize_tree.go +++ b/tree/serialize_tree.go @@ -54,8 +54,8 @@ func Serialize(root *BinaryTreeNode) string { return result } -// Unserialize unserializes a given string into a binary tree in O(n) time and O(n) space. -func Unserialize(s string) *BinaryTreeNode { +// Deserialize a string into a binary tree in O(n) time and O(n) space. +func Deserialize(s string) *BinaryTreeNode { if s == "" { return nil } diff --git a/tree/serialize_tree_test.go b/tree/serialize_tree_test.go index 03121db..d073fd0 100644 --- a/tree/serialize_tree_test.go +++ b/tree/serialize_tree_test.go @@ -5,8 +5,14 @@ import "testing" /* TestSerializeAndUnserializeBinaryTree tests solution(s) with the following signature and problem description: + type BinaryTreeNode struct { + Val int + Left *BinaryTreeNode + Right *BinaryTreeNode + } + func Serialize(root *BinaryTreeNode) string - func Unserialize(s string) *BinaryTreeNode + func Deserialize(s string) *BinaryTreeNode 4 @@ -16,8 +22,11 @@ TestSerializeAndUnserializeBinaryTree tests solution(s) with the following signa / \ / \ 3 5 -Write two functions to serialize and unserialize a binary tree like the one above to and -from a string like `4,2,6,nil,3,5,nil`. +Given a binary tree, write a serialize and deserialize function that turns it into a string representation +and back. + +For example given `4,2,6,nil,3,5,nil` representing the above tree, deserialize it to a *BinaryTreeNode, +and given the *BinaryTreeNode serialize it back to `4,2,6,nil,3,5,nil`. */ func TestSerializeAndUnserializeBinaryTree(t *testing.T) { tests := []string{ @@ -29,7 +38,7 @@ func TestSerializeAndUnserializeBinaryTree(t *testing.T) { "1,2,nil,4,nil,5,6", } for i, test := range tests { - if got := Serialize(Unserialize(test)); got != test { + if got := Serialize(Deserialize(test)); got != test { t.Fatalf("Failed test case #%d. Want %#v got %#v", i, test, got) } } diff --git a/tree/sorted_array_to_balanced_bsd_test.go b/tree/sorted_array_to_balanced_bsd_test.go index eb58446..150b2db 100644 --- a/tree/sorted_array_to_balanced_bsd_test.go +++ b/tree/sorted_array_to_balanced_bsd_test.go @@ -5,9 +5,23 @@ import "testing" /* TestBalancedBinarySearchTree tests solution(s) with the following signature and problem description: + type BinaryTreeNode struct { + Val int + Left *BinaryTreeNode + Right *BinaryTreeNode + } func BalancedBinarySearchTree(sorted []int) *BinaryTreeNode -Given a sorted array of integers like {1,2,3,4,5} return the root to a balanced BST. +Given a sorted slice of integers like return a string representing the integers as a Balanced Binary Tree (BST). + + 3 + / \ + / \ + 2 4 + / \ + 1 5 + +For example given return a *BinaryTreeNode that is the root element of the above tree. */ func TestBalancedBinarySearchTree(t *testing.T) { tests := []struct { diff --git a/tree/traverse_binary_tree_test.go b/tree/traverse_binary_tree_test.go index 8780f90..5107fc0 100644 --- a/tree/traverse_binary_tree_test.go +++ b/tree/traverse_binary_tree_test.go @@ -10,6 +10,8 @@ TestTraverseBinaryTree tests solution(s) with the following signature and proble func TraverseBinaryTree(root *BinaryTreeNode) ([]int, []int, []int) +Given a binary tree like the above return the tree in-order, pre-order, and post-order traversals. + 4 / \ / \ @@ -17,8 +19,11 @@ TestTraverseBinaryTree tests solution(s) with the following signature and proble / \ / \ 1 3 5 7 -Given a binary tree like the above one create three functions to traverse the -tree in-order, pre-order, and post-order. +For example given the above tree as "4,2,6,1,3,5,7" return: + + in-order traversal as [1,2,3,4,5,6,7], + pre-order traversal as [4,2,1,3,6,5,7], + post-order traversal as [1,3,2,5,7,6,4]. */ func TestTraverseBinaryTree(t *testing.T) { tests := []struct { @@ -32,7 +37,7 @@ func TestTraverseBinaryTree(t *testing.T) { {"4,2,6,nil,3,5", []int{2, 3, 4, 5, 6}, []int{4, 2, 3, 6, 5}, []int{3, 2, 5, 6, 4}}, } for i, test := range tests { - gotIn, gotPre, gotPost := TraverseBinaryTree(Unserialize(test.tree)) + gotIn, gotPre, gotPost := TraverseBinaryTree(Deserialize(test.tree)) if !slices.Equal(gotIn, test.in) { t.Fatalf("Failed in-order test case #%d. Want %#v got %#v", i, test.in, gotIn) }