diff --git a/04. Trees and graphs/4.3. list_of_depths.md b/04. Trees and graphs/4.3. list_of_depths.md new file mode 100644 index 0000000..7caa6eb --- /dev/null +++ b/04. Trees and graphs/4.3. list_of_depths.md @@ -0,0 +1,67 @@ +# 4.3. List of depths + +> Given a binary tree, create a linked list of all the nodes at each depth. If you have a tree with depth D, create D linked lists + +Create a breadth-first search and at each level create a linked list and append. I don't know how to create a breadth-first algorithm. + +## Hints + +* A hash table or array mapping from level numbers to nodes at that level might also be helpful +* First come up with an algorithm which does both depth-first search and breadth-first search + +## Solution + +We can transverse the graph any way we want, as long as we know which level we're on. We can slightly modify the pre-order traversal algorithm, where we pass in `level+1` to the next recursive call. + +```java +public static void createLevelLinkedList(TreeNode root, ArrayList> lists, int level) { + if (root == null) return; + LinkedList list = null; + if (lists.size() == level) { // Level not contained in list + list = new LinkedList(); + /* Levels are always traversed in order. So, if this is the first time we've visited level i, + * we must have seen levels 0 through i - 1. We can therefore safely add the level at the end. */ + lists.add(list); + } else { + list = lists.get(level); + } + list.add(root); + createLevelLinkedList(root.left, lists, level + 1); + createLevelLinkedList(root.right, lists, level + 1); +} +``` + +Alternatively, we can also implement a modification of the breadth-first search. + +```java +public static ArrayList> createLevelLinkedList(TreeNode root) { + ArrayList> result = new ArrayList>(); + + /* "Visit" the root */ + LinkedList current = new LinkedList(); + if (root != null) { + current.add(root); + } + + while (current.size() > 0) { + result.add(current); // Add previous level + LinkedList parents = current; // Go to next level + current = new LinkedList(); + for (TreeNode parent : parents) { + /* Visit the children */ + if (parent.left != null) { + current.add(parent.left); + } + if (parent.right != null) { + current.add(parent.right); + } + } + } + + return result; +} +``` + +Both algorithms run in O(N) time, but space efficiency? The first option uses O(logN) recursive calls (in a balanced tree), each of which adds a new level to the stack. The second solution, which is iterative doesn't need this extra space. + +Both solutions require returning O(N) data. The extra O(logN) used in the first approach is dwarfed by the data that must be returned. So both approaches are equally efficient. diff --git a/README.md b/README.md index 96a3f58..69c56cf 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ If you can't afford to buy the book, you can find a free pdf [here](https://leon * Find route between nodes in graph * Create minimal binary search tree from array +* Create a linked list for each depth in the tree ## Chapter 7 Object-oriented design