diff --git a/README.md b/README.md index 6b6fb24..2d3d96b 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,7 @@ Challenges, solutions, and unit tests are presented in the form of **IPython/Jup | Implement breadth-first search on a tree | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/tree_bfs/bfs_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/tree_bfs/bfs_solution.ipynb) | | Determine the height of a tree | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/tree_height/height_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/tree_height/height_solution.ipynb) | | Create a binary search tree with minimal height from a sorted array | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst_min/bst_min_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst_min/bst_min_solution.ipynb) | +| Create a linked list for each level of a binary tree | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/tree_level_lists/tree_level_lists_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/tree_level_lists/tree_level_lists_solution.ipynb) | | Implement a binary search tree | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst/bst_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/bst/bst_solution.ipynb) | | Implement depth-first search on a graph | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_dfs/dfs_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_dfs/dfs_solution.ipynb) | | Implement breadth-first search on a graph | [Challenge](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_bfs/bfs_challenge.ipynb)│[Solution](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/graph_bfs/bfs_solution.ipynb) | diff --git a/graphs_trees/tree_level_lists/__init__.py b/graphs_trees/tree_level_lists/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/graphs_trees/tree_level_lists/test_tree_level_lists.py b/graphs_trees/tree_level_lists/test_tree_level_lists.py new file mode 100644 index 0000000..9a9b4b2 --- /dev/null +++ b/graphs_trees/tree_level_lists/test_tree_level_lists.py @@ -0,0 +1,42 @@ +from nose.tools import assert_equal + + +class TestTreeLevelLists(object): + + def test_tree_level_lists(self): + node = Node(5) + insert(node, 3) + insert(node, 8) + insert(node, 2) + insert(node, 4) + insert(node, 1) + insert(node, 7) + insert(node, 6) + insert(node, 9) + insert(node, 10) + insert(node, 11) + + levels = create_level_lists(node) + results_list = [] + for level in levels: + results = Results() + for node in level: + results.add_result(node) + results_list.append(results) + + assert_equal(str(results_list[0]), '[5]') + assert_equal(str(results_list[1]), '[3, 8]') + assert_equal(str(results_list[2]), '[2, 4, 7, 9]') + assert_equal(str(results_list[3]), '[1, 6, 10]') + assert_equal(str(results_list[4]), '[11]') + + print('Success: test_tree_level_lists') + + +def main(): + test = TestTreeLevelLists() + test.test_tree_level_lists() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/graphs_trees/tree_level_lists/tree_level_lists_challenge.ipynb b/graphs_trees/tree_level_lists/tree_level_lists_challenge.ipynb new file mode 100644 index 0000000..ba7ff1c --- /dev/null +++ b/graphs_trees/tree_level_lists/tree_level_lists_challenge.ipynb @@ -0,0 +1,202 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Challenge Notebook" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Problem: Create a linked list for each level of a binary tree.\n", + "\n", + "* [Constraints](#Constraints)\n", + "* [Test Cases](#Test-Cases)\n", + "* [Algorithm](#Algorithm)\n", + "* [Code](#Code)\n", + "* [Unit Test](#Unit-Test)\n", + "* [Solution Notebook](#Solution-Notebook)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Constraints\n", + "\n", + "* Is this a binary search tree?\n", + " * Yes\n", + "* Can we assume we already have a Node class with an insert method?\n", + " * Yes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Cases\n", + "\n", + "* 5, 3, 8, 2, 4, 1, 7, 6, 9, 10, 11 -> [[5], [3, 8], [2, 4, 7, 9], [1, 6, 10], [11]]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Algorithm\n", + "\n", + "Refer to the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/tree_level_lists/tree_level_lists_solution.ipynb). If you are stuck and need a hint, the solution notebook's algorithm discussion might be a good place to start." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%run ../bst/bst.py\n", + "%load ../bst/bst.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def create_level_lists(root):\n", + " # TODO: Implement me\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Unit Test" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**The following unit test is expected to fail until you solve the challenge.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%run ../utils/results.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# %load test_tree_level_lists.py\n", + "from nose.tools import assert_equal\n", + "\n", + "\n", + "class TestTreeLevelLists(object):\n", + "\n", + " def test_tree_level_lists(self):\n", + " node = Node(5)\n", + " insert(node, 3)\n", + " insert(node, 8)\n", + " insert(node, 2)\n", + " insert(node, 4)\n", + " insert(node, 1)\n", + " insert(node, 7)\n", + " insert(node, 6)\n", + " insert(node, 9)\n", + " insert(node, 10)\n", + " insert(node, 11)\n", + "\n", + " levels = create_level_lists(node)\n", + " results_list = []\n", + " for level in levels:\n", + " results = Results()\n", + " for node in level:\n", + " results.add_result(node)\n", + " results_list.append(results)\n", + "\n", + " assert_equal(str(results_list[0]), '[5]')\n", + " assert_equal(str(results_list[1]), '[3, 8]')\n", + " assert_equal(str(results_list[2]), '[2, 4, 7, 9]')\n", + " assert_equal(str(results_list[3]), '[1, 6, 10]')\n", + " assert_equal(str(results_list[4]), '[11]')\n", + "\n", + " print('Success: test_tree_level_lists')\n", + "\n", + "\n", + "def main():\n", + " test = TestTreeLevelLists()\n", + " test.test_tree_level_lists()\n", + "\n", + "\n", + "if __name__ == '__main__':\n", + " main()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution Notebook\n", + "\n", + "Review the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/graphs_trees/tree_level_lists/tree_level_lists_solution.ipynb) for a discussion on algorithms and code solutions." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.10" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/graphs_trees/tree_level_lists/tree_level_lists_solution.ipynb b/graphs_trees/tree_level_lists/tree_level_lists_solution.ipynb new file mode 100644 index 0000000..dbfc106 --- /dev/null +++ b/graphs_trees/tree_level_lists/tree_level_lists_solution.ipynb @@ -0,0 +1,239 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Solution Notebook" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Problem: Create a linked list for each level of a binary tree.\n", + "\n", + "* [Constraints](#Constraints)\n", + "* [Test Cases](#Test-Cases)\n", + "* [Algorithm](#Algorithm)\n", + "* [Code](#Code)\n", + "* [Unit Test](#Unit-Test)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Constraints\n", + "\n", + "* Is this a binary search tree?\n", + " * Yes\n", + "* Can we assume we already have a Node class with an insert method?\n", + " * Yes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Cases\n", + "\n", + "* 5, 3, 8, 2, 4, 1, 7, 6, 9, 10, 11 -> [[5], [3, 8], [2, 4, 7, 9], [1, 6, 10], [11]]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Algorithm\n", + "\n", + "We can use either a depth-first or a breadth-first search. Intuitively, it seems like a breadth-first search might be a better fit as we are creating a linked list for each level.\n", + "\n", + "We can use a modified breadth-first search that keeps track of parents as we build the linked list for the current level.\n", + "\n", + "* Append the root to the current level's linked list `current`\n", + "* While the `current` is not empty:\n", + " * Add `current` to `results`\n", + " * Set `parents` to `current` to prepare to go one level deeper\n", + " * Clear `current` so it can hold the next level\n", + " * For each `parent` in `parents`, add the children to `current`\n", + "* Return the results\n", + " \n", + "Complexity:\n", + "* Time: O(n)\n", + "* Space: O(n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%run ../bst/bst.py" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def create_level_lists(root):\n", + " if root is None:\n", + " return\n", + " results = []\n", + " current = []\n", + " parents = []\n", + " current.append(root)\n", + " while current:\n", + " results.append(current)\n", + " parents = list(current)\n", + " current = []\n", + " for parent in parents:\n", + " if parent.left is not None:\n", + " current.append(parent.left)\n", + " if parent.right is not None:\n", + " current.append(parent.right)\n", + " return results" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Unit Test" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%run ../utils/results.py" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting test_tree_level_lists.py\n" + ] + } + ], + "source": [ + "%%writefile test_tree_level_lists.py\n", + "from nose.tools import assert_equal\n", + "\n", + "\n", + "class TestTreeLevelLists(object):\n", + "\n", + " def test_tree_level_lists(self):\n", + " node = Node(5)\n", + " insert(node, 3)\n", + " insert(node, 8)\n", + " insert(node, 2)\n", + " insert(node, 4)\n", + " insert(node, 1)\n", + " insert(node, 7)\n", + " insert(node, 6)\n", + " insert(node, 9)\n", + " insert(node, 10)\n", + " insert(node, 11)\n", + "\n", + " levels = create_level_lists(node)\n", + " results_list = []\n", + " for level in levels:\n", + " results = Results()\n", + " for node in level:\n", + " results.add_result(node)\n", + " results_list.append(results)\n", + "\n", + " assert_equal(str(results_list[0]), '[5]')\n", + " assert_equal(str(results_list[1]), '[3, 8]')\n", + " assert_equal(str(results_list[2]), '[2, 4, 7, 9]')\n", + " assert_equal(str(results_list[3]), '[1, 6, 10]')\n", + " assert_equal(str(results_list[4]), '[11]')\n", + "\n", + " print('Success: test_tree_level_lists')\n", + "\n", + "\n", + "def main():\n", + " test = TestTreeLevelLists()\n", + " test.test_tree_level_lists()\n", + "\n", + "\n", + "if __name__ == '__main__':\n", + " main()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Success: test_tree_level_lists\n" + ] + } + ], + "source": [ + "%run -i test_tree_level_lists.py" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.10" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +}