Ace Your Coding Interview — Blind 75 Solved and Explained — Part 6.1 Trees

Uluc Ozdenvar
8 min readJul 11, 2022

--

Moving on to what I believe to be the most important chapter, I will break it down into 2 sections. For this section, I will walk through the first 7 questions and finish the remaining 6 questions in part 2.

However, before attempting these questions learning a few core concepts in trees are imperative to best approach the questions. Otherwise, it’s exponentially harder to figure out the correct approaches.

Data Structures & Techniques:

  • Binary Search Tree
  • Depth First Search
  • Breadth-First Search
  • Trie
  • PreOrder, InOrder, and PostOrder Sorting
  • Recursion

Understanding these data structures and algorithms will allow us to solve the problems with the correct approaches. Some of these questions were personally hard to figure out and my solutions weren’t optimal I have linked solutions that I use in this tutorial that are completely from the leetcode discussion that I believe make the most sense.

As always the link to the original Blind 75 is below:

Question 1 — Maximum Depth of Binary Tree

A Solution to Max Depth.

The solution from: https://leetcode.com/problems/maximum-depth-of-binary-tree/discuss/34216/Simple-solution-using-Java

Our Approach:

  1. If our root is empty we return 0 because there is no depth.
  2. We recursively check left and right subtrees, every time we do this we add one to our max depth as we know the roots to be not empty.

Question 2 — Same Tree

A Solution to Same Tree

Our Approach:

  1. For trees to be the same, nodes have to match. We check if both tree nodes are empty. If both are empty, then we found two identical trees.
  2. If one tree is empty and one isn’t they cannot be the same. Thus, we return false if only one is null and the other isn’t
  3. We compare the values of each tree node, if equal we are going to keep checking for left and right subtrees.
  4. If values don’t match, trees cannot be the same. Thus, we return false.

Question 3 — Invert/Flip Binary Tree

A Solution to Invert Binary Tree

Inverting a binary tree means we have to swap all the left-right and subtrees recursively. The best way to approach this is through a breadth-first search since it utilizes level-by-level traversal.

Our Approach:

  1. Check if the root is empty, if so return null.
  2. Declare a new queue that can be used to store the nodes. To start offer the root itself to the queue.
  3. Next, we run the breadth-first search algorithm with some minor modifications. Each time we start we poll the contents of the queue.
  4. The next step is the inverting of our tree: Swap the left and right nodes.
  5. Once our swap occurs, we need to repeat this operation on our left and right subtrees. We need to offer the left and right nodes to our queue so the previous operation can be repeated. Before we add anything to the queue, make sure it isn’t null as it would cause a null pointer exception.

Question 4 — Binary Tree Maximum Path Sum

A Solution to Binary Tree Maximum Path Sum

Solution from: https://leetcode.com/problems/binary-tree-maximum-path-sum/discuss/39875/Elegant-Java-solution

Our Approach:

  1. We declare a global variable to keep track of our maximum path sum.
  2. We create a helper method to find the max path sum.
  3. As always, check to see if the root is null; if null, return zero as there can be no path sum.
  4. After we check the root, we need to evaluate the left and right subtrees. During our left and right subtree evaluation, we need to account for negative values. If a negative value is found 0 is always a greater path sum. To account for this we add a Math.max() function.
  5. After evaluating our subtrees, we need to update our global maximum. We compare our current maximum to the sum of left, right, and root nodes. This is because left → root → right forms a path itself.
  6. We need to return the largest path value existent in a node. This is done by taking the root value and seeing if the right or left node is larger and adding that to the root. To visualize, work your way from the bottom up. For a path, we can only visit the left, root, and right nodes at the very root of the tree. As we move up towards the top we need to pick if the left or right side of each node provides a higher path sum.
  7. Finally, we go back to the main method of our path sum. We call our helper method to calculate our max value.

Question 5 — Binary Tree Level Order Traversal

A Solution to Binary Tree Level Order Traversal

Our Approach:

  1. Create a results list of lists to fill and return upon end of method
  2. Check if the root is empty, if so return null.
  3. Create a queue to add nodes into during breadth-first search.
  4. Run a breadth-first search on our tree. This is done by iterating until our queue which holds nodes are empty.
  5. We find the size of our current level, this is needed so we can loop through the items. This is done by checking the size of our queue as it represents all the nodes available inside it.
  6. We create a simple list to hold onto our current level’s values. Once at the end of our list, we add this list to our results variable.
  7. We iterate the amount of levels available to us. During this, we poll our queue to get the top element and add it to our current level. After we have added our current level, we need to prepare for the next one. This is done by checking the left and right subtrees to see if they posses valid nodes. If so, we add our subtrees to the queue to add for the next levels.
  8. When the iterations of our levels are complete add our current level to the result array.
  9. Return results.

Question 6 — Serialize and Deserialize Binary Tree

A Solution to Serialize and Deserialize Binary Tree

Solution: https://leetcode.com/problems/serialize-and-deserialize-binary-tree/discuss/74253/Easy-to-understand-Java-Solution

Our Approach:

  1. We need two global constants for looking at null nodes and delimiter.
  2. We are going to create 4 methods for this question. A serializer, a serializer helper (buildString), a deserializer, and a deserializer helper (buildTree).
  3. Serialize method create a StringBuilder to store the serialized string. This StringBuilder and root of the tree is passed into the helper method. Upon the return StringBuilder is converted to string and returned.
  4. BuildString method checks to see if the node is null, if so it adds the null node constant followed by a comma (delimiter). If not, we add our current node value followed by the comma. We also need to work our way down the subtrees so we recursively check the left and right subtrees.
  5. Deserialize method takes in a string and converts it into a node. We create a queue to store our nodes. We add all the values from our string into our queue. This is done by taking our string and converting it into a list and utilizing the addAll() function. Finally, we need to return the tree itself, this is done by calling our helper function to generate the tree.
  6. BuildTree method takes in a queue of strings and converts them into a tree. Before we start we check if our initial node is null. If so we return a null. If not we continue with our other nodes. We grab the next available string value from our queue and assign it to a node. We take this node and recursively build out the left and right subtrees. Finally, return the node itself which represents the tree.

Question 7 — Subtree of Another Tree

A Solution to Subtree of Another Tree

Our Approach:

  1. We start by checking if our tree is null, if so return false as subtree couldn’t exist.
  2. If not null, we need to run a depth-first search on on our root and subtree to check if a valid subtree can be found.
  3. If our search fails, we need to check if the subtree exists in our left or right subtree.
  4. For our depth-first search, we check if both root and subtree is empty, if so return true.
  5. If only one of the two is empty we return false as trees don’t match.
  6. If the values of the root and subtree don’t match we return false as trees aren’t equal.
  7. If the values do end up being equal we need to check the left subtree of the root with the left subtree of the initial subtree recursively, as well as, the right subtree of the root with the right subtree of the initial subtree.

Posts in the Series

Arrays: https://medium.com/@ulucozdenvar01/ace-your-coding-interview-blind-75-solved-and-explained-part-1-arrays-4692c04891e0

Binary: https://medium.com/@ulucozdenvar01/ace-your-coding-interview-blind-75-solved-part-2-binary-27160cd04462

Intervals: https://medium.com/@ulucozdenvar/ace-your-coding-interview-blind-75-solved-and-explained-part-3-intervals-ef6adbcc93fe

LinkedList: https://medium.com/@ulucozdenvar/ace-your-coding-interview-blind-75-solved-and-explained-part-4-linked-list-6c05a9a92b75

String: https://medium.com/@ulucozdenvar/ace-your-coding-interview-blind-75-solved-and-explained-part-5-string-3cae5fd56f36

Trees Part 2: https://medium.com/@ulucozdenvar/ace-your-coding-interview-blind-75-solved-and-explained-part-6-2-trees-continued-64cf6f60350

Matrix: https://medium.com/@ulucozdenvar/ace-your-coding-interview-blind-75-solved-and-explained-part-7-matrix-244b4b308bfc

Heap: https://medium.com/@ulucozdenvar/ace-your-coding-interview-blind-75-solved-and-explained-part-8-heaps-560ab652094f

Dynamic Programming: Coming Soon

Graph: Coming Soon

--

--