Skip to content

Add details to tree problems #179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion queue/symmetrical_binary_tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
8 changes: 4 additions & 4 deletions tree/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -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
Expand All @@ -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.

Expand All @@ -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

Expand Down
9 changes: 6 additions & 3 deletions tree/autocompletion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
13 changes: 11 additions & 2 deletions tree/evaluate_expression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 6 additions & 3 deletions tree/reverse_binary_tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,25 @@ 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
/ \
2 3
/ \ / \
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 {
Expand All @@ -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)
}
}
Expand Down
4 changes: 2 additions & 2 deletions tree/serialize_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
17 changes: 13 additions & 4 deletions tree/serialize_tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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{
Expand All @@ -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)
}
}
Expand Down
16 changes: 15 additions & 1 deletion tree/sorted_array_to_balanced_bsd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
11 changes: 8 additions & 3 deletions tree/traverse_binary_tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@ 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
/ \
/ \
2 6
/ \ / \
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 {
Expand All @@ -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)
}
Expand Down