Trees Flashcards

1
Q

Validate Binary Search Tree (Medium)

Given a binary tree, determine if it is a valid binary search tree (BST).

Assume a BST is defined as follows:

The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than the node’s key.
Both the left and right subtrees must also be binary search trees.

A

helper(root, null, null) // lower, upper

if node = null, return true
if lower set and val <= lower return false
if upper set and val >= upper return false

if !helper(node.right, val, upper) return false
if !helper(node.left, lower, val) return false

return true

Time - O(n)
Space - O(n) / O(log n) average (height of tree)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Binary Tree Level Order Traversal (Medium)

Given a binary tree, return the level order traversal of its nodes’ values. (ie, from left to right, level by level).

A

create traversal
push root node to queue
BFS, create level for each iteration for queue.length
push node to level
push left/right children if exist to queue
push level to traversal

Time - O(n)
Space - O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Binary Tree Zigzag Level Order Traversal (Medium)

Given a binary tree, return the zigzag level order traversal of its nodes’ values. (ie, from left to right, then right to left for the next level and alternate between).

A

create traversal
push root node to queue
set leftToRight to true
BFS, create level for each iteration for queue.length
if leftToRight, push node to level, otherwise unshift node to level
push left/right children if exist to queue
push level to traversal

Time - O(n)
Space - O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Construct Binary Tree from Preorder and Inorder Traversal (Medium)

Given preorder and inorder traversal of a tree, construct the binary tree.

A

set preIndex = 0
iterate through inorder indexMap.set(inorder[i], i)
helper(0, inorder.length)

helper(inLeft, inRight)
if inLeft = inRight return null
rootVal = preorder[preIndex]
root = new Node(rootVal)
index = indexMap.get(rootVal)
preIndex++
root.left = helper(inLeft, index)
root.right = helper(index + 1, inRight)
return root

Time - O(n)
Space - O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Construct Binary Tree from Inorder and Postorder Traversal (Medium)

Given inorder and postorder traversal of a tree, construct the binary tree.

A

set postIndex = postorder.length - 1
iterate through inorder indexMap.set(inorder[i], i)
helper(0, inorder.length - 1)

helper(inLeft, inRight)
if inLeft > inRight return null
rootVal = postorder[postIndex]
root = new Node(rootVal)
index = indexMap.get(rootVal)
postIndex--
root.right = helper(index + 1, inRight)
root.left = helper(inLeft, index - 1)
return root

Time - O(n)
Space - O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Minimum Depth of Binary Tree (Easy)

Given a binary tree, find its minimum depth.

The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.

A

set depth = 0
BFS
when you reach a leaf return depth
depth++ after each BFS cycle

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Flatten Binary Tree to Linked List (Medium)

Given a binary tree, flatten it to a linked list in-place.

A

flattenTree(root)

if node = null return null
if node.left = null and node.right = null return node
leftTail = flattenTree(node.left)
rightTail = flattenTree(node.right)

if leftTail
leftTail.right = node.right
node.right = node.left
node.left = null

return rightTail = null ? leftTail : rightTail

Time - O(n)
Space - O(n) / O(log n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Binary Tree Maximum Path Sum (Hard)

Given a non-empty binary tree, find the maximum path sum.

For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.

A

maxSum = -Infinity
maxGain(root)
return maxSum

maxGain:
if node = null return 0
leftGain = max(maxGain(node.left), 0)
rightGain = max(maxGain(node.right,  0)
sum = node.val + leftGain + rightGain
maxSum = max(sum, maxSum)
return node.val + max(leftGain, rightGain)

Time - O(n)
Space - O(n) / O(log n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Binary Search Tree Iterator (Medium)

Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST.

Calling next() will return the next smallest number in the BST.

A

initialize with empty stack
leftMostInOrder(root)

leftMostInOrder:
while node != null
stack.push(node)
node = node.left

next:
nextNode = stack.pop()
if nextNode.right leftMostInOrder(nextNode.right)
return nextNode.val

hasNext:
return this.stack.length > 0

Time - O(n)
Space - O(n) / O(log n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Binary Tree Right Side View (Medium)

Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.

A
create view
push node to queue
BFS
iterate for queue.length / size
if i === size - 1 (only push to view for last node in a level)
view.push(node.val)

Time - O(n)
Space - O(n) / O(log n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Kth Smallest Element in a BST (Medium)

Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.

A

create iterator
loop from i = 0, i < k
ans = iterator.next().value
return ans

inOrderTraversal*
if node.left yield* inOrderTraversal(node.left)
yield node.val
if node.right yield* inOrderTraversal(node.right)

Time - O(k)
Space - O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Lowest Common Ancestor of a Binary Tree (Medium)

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

A

if root = null or root = p or root = q
return root

L = lca(root.left, p, q)
R = lca(root.right, p, q)

return (L && R) ? root : (L || R)

Time - O(n)
Space - O(n) / O(log n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Binary Tree Paths (Easy)

Given a binary tree, return all root-to-leaf paths.

A
paths = []
push { node: root, path: '' } to queue
BFS
shift node/path off queue
path += ->${node.val}

push left/right to queue if exist with path

if !node.left and !node.right push path to paths array

Time - O(n)
Space - O(n) / O(log n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Closest Binary Search Tree Value (Easy)

Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target.

A

closest = root.val
while (root != null)
closest = abs(root.val - target) < abs(closest - target) ? root.val : closest
root = target < root.val ? root.left : root.right

return closest;

Time - O(n)
Space - O(1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Serialize and Deserialize Binary Tree (Hard)

Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.

Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure.

A

serialize as dfs preorder traversal (root, left, right)

deserialize
rdeserialize(data)
if traversal[0] = null
traversal.splice(0, 1) return null

node = new Node(traversal[0])
traversal.splice(0, 1)
node.left = rdeserialize(traversal)
node.right = rdeserialize(traversal)
return node

Time - O(n)
Space - O(n)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Binary Tree Vertical Order Traversal (Medium)

Given a binary tree, return the vertical order traversal of its nodes’ values. (ie, from top to bottom, column by column).

If two nodes are in the same row and column, the order should be from left to right.

A

BFS
add node, column: 0 to queue
create columnMap
minColumn, maxColumn = 0

shift node, column off queue
minColumn = min(minColumn, column)
maxColumn = max(maxColumn, column)
if columnMap does not have column
columnMap.set(column, [node.val])
otherwise push node.val to columnMap

if node.left push node.left, column - 1 to queue
if node.right push node.right column + 1 to queue

iterate through columnMap from min to max column
push columns to result

Time - O(n)
Space - O(n)

17
Q

Diameter of Binary Tree (Easy)

Given a binary tree, you need to compute the length of the diameter of the tree. The diameter of a binary tree is the length of the longest path between any two nodes in a tree. This path may or may not pass through the root.

A

diameter = 0
dfs(root)

dfs:
if node = null return 0
L = dfs(node.left)
R = dfs(node.right)
diameter = max(diameter, L + R)
return 1 + max(L, R)

Time - O(n)
Space - O(n) / O(log n)

18
Q

Average of Levels in Binary Tree (Easy)

Given a non-empty binary tree, return the average value of the nodes on each level in the form of an array.

A
BFS
levelSum = 0
levelSize = queue.length
sum up node.vals in level
result.push(levelSum / levelSize)

Time - O(n)
Space - O(n) / O(log n)

19
Q

Convert Binary Search Tree to Sorted Doubly Linked List (Medium)

Convert a Binary Search Tree to a sorted Circular Doubly-Linked List in place.

You can think of the left and right pointers as synonymous to the predecessor and successor pointers in a doubly-linked list. For a circular doubly linked list, the predecessor of the first element is the last element, and the successor of the last element is the first element.

We want to do the transformation in place. After the transformation, the left pointer of the tree node should point to its predecessor, and the right pointer should point to its successor. You should return the pointer to the smallest element of the linked list.

A

[leftMost, rightMost] = flattenTree(root)
rightMost.right = leftMost
leftMost.left = rightMost
return leftMost

flattenTree:
if node.left = null leftMost = node
else
[leftTreeLeftMost, leftTreeRightMost] = flattenTree(node.left)
connectNodes(leftTreeRightMost, node)
if node.right = null rightMost = node
else
[rightTreeLeftMost, rightTreeRightMost] = flattenTree(node.right)
connectNodes(node, rightTreeLeftMost)
return [leftMost, rightMost]

connectNodes(left, right)

left. right = right
right. left = left

Time - O(n)
Space - O(n) / O(log n)

20
Q

Smallest Subtree with all the Deepest Nodes (Medium)

Given a binary tree rooted at root, the depth of each node is the shortest distance to the root.

A node is deepest if it has the largest depth possible among any node in the entire tree.

The subtree of a node is that node, plus the set of all descendants of that node.

Return the node with the largest depth such that it contains all the deepest nodes in its subtree.

A

BFS to find deepest nodes
deepestNodes = [] for each level of BFS
push node when i = 0 and i = size - 1 to get first and last node of deepest level

if only one deepest node, return it
otherwise use lca with 2 deepest nodes

lca:
if (node = null or node = p or node = q) return node
L = lca(node.left, p, q)
R = lca(node.right, p, q)

return (L && R) ? node : (L || R)

Time - O(n)
Space - O(n) / O(log n)

21
Q

Range Sum of BST (Easy)

Given the root node of a binary search tree, return the sum of values of all nodes with value between L and R (inclusive).

The binary search tree is guaranteed to have unique values.

A

sum = 0
inOrderTraversal(node, L, R, (node) =>.{
sum += node.val
})

inOrderTraversal:
if node = null return
if node.val > L inOrderTraversal(node.left, L, R, visit)
if node.val >= L && node.val <= R visit(node)
if node.val < R inOrderTraversal(node.right, L, R, visit)

Time - O(n)
Space - O(n) / O(log n)

22
Q

Check Completeness of a Binary Tree (Medium)

Given a binary tree, determine if it is a complete binary tree.

Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.

A

BFS
push node, code: 0 to queue
code is index in heap style array
shift node/code from queue
push code to traversal
if node.left push node.left code 2 * code + 1 to queue
if node.right push node.right code 2 * code + 2 to queue

return traversal.length - 1 = traversal[traversal.length - 1]

Time - O(n)
Space - O(n) / O(log n)