Skip to content

Commit 079205d

Browse files
authored
Merge pull request ByteByteGoHq#41 from marttp/kotlin-tree
Kotlin - Chapter 11: Trees
2 parents ee65a1f + c0ff1a4 commit 079205d

14 files changed

+556
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import ds.TreeNode
2+
3+
/*
4+
Definition of TreeNode:
5+
6+
data class TreeNode(
7+
var value: Int,
8+
var left: TreeNode? = null,
9+
var right: TreeNode? = null
10+
)
11+
*/
12+
13+
fun balancedBinaryTreeValidation(root: TreeNode?): Boolean {
14+
return getHeightImbalance(root) != -1
15+
}
16+
17+
fun getHeightImbalance(node: TreeNode?): Int {
18+
// Base case: if the node is null, its height is 0.
19+
if (node == null) {
20+
return 0
21+
}
22+
// Recursively get the height of the left and right subtrees. If
23+
// either subtree is imbalanced, propagate -1 up the tree.
24+
val leftHeight = getHeightImbalance(node.left)
25+
val rightHeight = getHeightImbalance(node.right)
26+
if (leftHeight == -1 || rightHeight == -1) {
27+
return -1
28+
}
29+
// If the current node's subtree is imbalanced
30+
// (height difference > 1), return -1.
31+
if (Math.abs(leftHeight - rightHeight) > 1) {
32+
return -1
33+
}
34+
// Return the height of the current subtree.
35+
return 1 + Math.max(leftHeight, rightHeight)
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import ds.TreeNode
2+
3+
/*
4+
Definition of TreeNode:
5+
6+
data class TreeNode(
7+
var value: Int,
8+
var left: TreeNode? = null,
9+
var right: TreeNode? = null
10+
)
11+
*/
12+
13+
fun binarySearchTreeValidation(root: TreeNode?): Boolean {
14+
// Start validation at the root node. The root node can contain any
15+
// value, so set the initial lower and upper bounds to -infinity and
16+
// +infinity, respectively.
17+
return isWithinBounds(root, Int.MIN_VALUE, Int.MAX_VALUE)
18+
}
19+
20+
fun isWithinBounds(node: TreeNode?, lowerBound: Int, upperBound: Int): Boolean {
21+
// Base case: if the node is null, it satisfies the BST condition.
22+
if (node == null) {
23+
return true
24+
}
25+
// If the current node's value is not within the valid bounds, this
26+
// tree is not a valid BST.
27+
if (node.value <= lowerBound || node.value >= upperBound) {
28+
return false
29+
}
30+
// If the left subtree isn't a BST, this tree isn't a BST.
31+
if (!isWithinBounds(node.left, lowerBound, node.value)) {
32+
return false
33+
}
34+
// Otherwise, return true if the right subtree is also a BST.
35+
return isWithinBounds(node.right, node.value, upperBound)
36+
}

kotlin/Trees/BinaryTreeColumns.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import java.util.LinkedList
2+
import ds.TreeNode
3+
4+
/*
5+
Definition of TreeNode:
6+
7+
data class TreeNode(
8+
var value: Int,
9+
var left: TreeNode? = null,
10+
var right: TreeNode? = null
11+
)
12+
*/
13+
14+
fun binaryTreeColumns(root: TreeNode?): List<List<Int>> {
15+
if (root == null) {
16+
return emptyList()
17+
}
18+
val columnMap = hashMapOf<Int, MutableList<Int>>()
19+
var leftmostColumn = 0
20+
var rightmostColumn = 0
21+
val queue = LinkedList<Pair<TreeNode?, Int>>()
22+
queue.add(root to 0)
23+
24+
while (queue.isNotEmpty()) {
25+
val (node, column) = queue.removeFirst()
26+
if (node != null) {
27+
// Add the current node's value to its corresponding list in the hash
28+
// map.
29+
columnMap.computeIfAbsent(column) { mutableListOf() }.add(node.value)
30+
leftmostColumn = minOf(leftmostColumn, column)
31+
rightmostColumn = maxOf(rightmostColumn, column)
32+
// Add the current node's children to the queue with their respective
33+
// column ids.
34+
queue.add(node.left to column - 1)
35+
queue.add(node.right to column + 1)
36+
}
37+
}
38+
39+
// Construct the output list by collecting values from each column in the hash
40+
// map in the correct order.
41+
return (leftmostColumn..rightmostColumn).map { columnMap[it] ?: emptyList() }
42+
}

kotlin/Trees/BinaryTreeSymmetry.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import ds.TreeNode
2+
3+
/*
4+
Definition of TreeNode:
5+
6+
data class TreeNode(
7+
var value: Int,
8+
var left: TreeNode? = null,
9+
var right: TreeNode? = null
10+
)
11+
*/
12+
13+
fun binaryTreeSymmetry(root: TreeNode?): Boolean {
14+
if (root == null) {
15+
return true
16+
}
17+
return compareTrees(root.left, root.right)
18+
}
19+
20+
fun compareTrees(node1: TreeNode?, node2: TreeNode?): Boolean {
21+
// Base case: if both nodes are null, they're symmetric.
22+
if (node1 == null && node2 == null) {
23+
return true
24+
}
25+
// If one node is null and the other isn't, they aren't symmetric.
26+
if (node1 == null || node2 == null) {
27+
return false
28+
}
29+
// If the values of the current nodes don't match, trees aren't symmetric.
30+
if (node1.value != node2.value) {
31+
return false
32+
}
33+
// Compare the 'node1's left subtree with 'node2's right subtree. If these
34+
// aren't symmetric, the whole tree is not symmetric.
35+
if (!compareTrees(node1.left, node2.right)) {
36+
return false
37+
}
38+
// Compare the 'node1's right subtree with 'node2's left subtree.
39+
return compareTrees(node1.right, node2.left)
40+
}

kotlin/Trees/BuildBinaryTree.kt

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import ds.TreeNode
2+
3+
/*
4+
Definition of TreeNode:
5+
6+
data class TreeNode(
7+
var value: Int,
8+
var left: TreeNode? = null,
9+
var right: TreeNode? = null
10+
)
11+
*/
12+
13+
fun buildBinaryTree(preorder: List<Int>, inorder: List<Int>): TreeNode? {
14+
val inorderIndexesMap = hashMapOf<Int, Int>()
15+
val preorderIndex = intArrayOf(0)
16+
// Populate the hash map with the inorder values and their indexes.
17+
for (i in inorder.indices) {
18+
inorderIndexesMap[inorder[i]] = i
19+
}
20+
// Build the tree and return its root node.
21+
return buildSubtree(0, inorder.size - 1, preorder, inorder, preorderIndex, inorderIndexesMap)
22+
}
23+
24+
fun buildSubtree(
25+
left: Int,
26+
right: Int,
27+
preorder: List<Int>,
28+
inorder: List<Int>,
29+
preorderIndex: IntArray,
30+
inorderIndexesMap: Map<Int, Int>
31+
): TreeNode? {
32+
// Base case: if no elements are in this range, return null.
33+
if (left > right) {
34+
return null
35+
}
36+
val value = preorder[preorderIndex[0]]
37+
// Set 'inorderIndex' to the index of the same value pointed at by
38+
// 'preorderIndex'.
39+
val inorderIndex = inorderIndexesMap[value]!!
40+
val node = TreeNode(value)
41+
// Advance 'preorderIndex' so it points to the value of the next
42+
// node to be created.
43+
preorderIndex[0]++
44+
// Build the left and right subtrees and connect them to the current
45+
// node.
46+
node.left =
47+
buildSubtree(
48+
left,
49+
inorderIndex - 1,
50+
preorder,
51+
inorder,
52+
preorderIndex + 1,
53+
inorderIndexesMap
54+
)
55+
node.right =
56+
buildSubtree(
57+
inorderIndex + 1,
58+
right,
59+
preorder,
60+
inorder,
61+
preorderIndex + inorderIndex - left + 1,
62+
inorderIndexesMap
63+
)
64+
return node
65+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import java.util.Stack
2+
import ds.TreeNode
3+
4+
/*
5+
Definition of TreeNode:
6+
7+
data class TreeNode(
8+
var value: Int,
9+
var left: TreeNode? = null,
10+
var right: TreeNode? = null
11+
)
12+
*/
13+
14+
fun invertBinaryTreeIterative(root: TreeNode?): TreeNode? {
15+
if (root == null) return null
16+
val stack = Stack<TreeNode>()
17+
stack.push(root)
18+
while (stack.isNotEmpty()) {
19+
val node = stack.pop()
20+
// Swap the left and right subtrees of the current node.
21+
val temp = node.left
22+
node.left = node.right
23+
node.right = temp
24+
// Push the left and right subtrees onto the stack.
25+
if (node.left != null) {
26+
stack.push(node.left)
27+
}
28+
if (node.right != null) {
29+
stack.push(node.right)
30+
}
31+
}
32+
return root
33+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import ds.TreeNode
2+
3+
/*
4+
Definition of TreeNode:
5+
6+
data class TreeNode(
7+
var value: Int,
8+
var left: TreeNode? = null,
9+
var right: TreeNode? = null
10+
)
11+
*/
12+
13+
fun invertBinaryTreeRecursive(root: TreeNode?): TreeNode? {
14+
// Base case: If the node is null, there's nothing to invert.
15+
if (root == null) {
16+
return null
17+
}
18+
// Swap the left and right subtrees of the current node.
19+
val temp = root.left
20+
root.left = root.right
21+
root.right = temp
22+
// Recursively invert the left and right subtrees.
23+
invertBinaryTreeRecursive(root.left)
24+
invertBinaryTreeRecursive(root.right)
25+
return root
26+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import java.util.Stack
2+
import ds.TreeNode
3+
4+
/*
5+
Definition of TreeNode:
6+
7+
data class TreeNode(
8+
var value: Int,
9+
var left: TreeNode? = null,
10+
var right: TreeNode? = null
11+
)
12+
*/
13+
14+
fun kthSmallestNumberInBSTIterative(root: TreeNode?, k: Int): Int {
15+
val stack = Stack<TreeNode>()
16+
var node = root
17+
// Copy 'k' to a mutable variable so we can decrement it.
18+
var k = k
19+
while (stack.isNotEmpty() || node != null) {
20+
// Move to the leftmost node and add nodes to the stack as we go so they
21+
// can be processed in future iterations.
22+
while (node != null) {
23+
stack.push(node)
24+
node = node.left
25+
}
26+
// Pop the top node from the stack to process it, and decrement 'k'.
27+
node = stack.pop()
28+
k--
29+
// If we have processed 'k' nodes, return the value of the 'k'th smallest
30+
// node.
31+
if (k == 0) {
32+
return node.value
33+
}
34+
// Move to the right subtree.
35+
node = node.right
36+
}
37+
return -1
38+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import ds.TreeNode
2+
3+
/*
4+
Definition of TreeNode:
5+
6+
data class TreeNode(
7+
var value: Int,
8+
var left: TreeNode? = null,
9+
var right: TreeNode? = null
10+
)
11+
*/
12+
13+
fun kthSmallestNumberInBSTRecursive(root: TreeNode?, k: Int): Int {
14+
val sortedList = inorder(root)
15+
return sortedList[k - 1]
16+
}
17+
18+
// Inorder traversal function to attain a sorted list of nodes from the BST.
19+
fun inorder(node: TreeNode?): List<Int> {
20+
if (node == null) {
21+
return emptyList()
22+
}
23+
return inorder(node.left) + listOf(node.value) + inorder(node.right)
24+
}

kotlin/Trees/LowestCommonAncestor.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import ds.TreeNode
2+
3+
/*
4+
Definition of TreeNode:
5+
6+
data class TreeNode(
7+
var value: Int,
8+
var left: TreeNode? = null,
9+
var right: TreeNode? = null
10+
)
11+
*/
12+
13+
fun lowestCommonAncestor(root: TreeNode?, p: TreeNode?, q: TreeNode?): TreeNode? {
14+
var lca: MutableList<TreeNode?> = mutableListOf(null)
15+
dfs(root, p, q, lca)
16+
return lca[0]
17+
}
18+
19+
fun dfs(node: TreeNode?, p: TreeNode?, q: TreeNode?, lca: MutableList<TreeNode?>): Boolean {
20+
// Base case: a null node is neither 'p' nor 'q'.
21+
if (node == null) {
22+
return false
23+
}
24+
val nodeIsPOrQ = node == p || node == q
25+
// Recursively determine if the left and right subtrees contain 'p'
26+
// or 'q'.
27+
val leftContainsPOrQ = dfs(node.left, p, q, lca)
28+
val rightContainsPOrQ = dfs(node.right, p, q, lca)
29+
// If two of the above three variables are true, the current node is
30+
// the LCA.
31+
if ((nodeIsPOrQ && leftContainsPOrQ) ||
32+
(nodeIsPOrQ && rightContainsPOrQ) ||
33+
(leftContainsPOrQ && rightContainsPOrQ)
34+
) {
35+
lca[0] = node
36+
}
37+
38+
// Return true if the current subtree contains 'p' or 'q'.
39+
return nodeIsPOrQ || leftContainsPOrQ || rightContainsPOrQ
40+
}

0 commit comments

Comments
 (0)