diff --git a/linked_lists/remove_duplicates/__init__.py b/linked_lists/remove_duplicates/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/linked_lists/remove_duplicates/remove_duplicates_challenge.ipynb b/linked_lists/remove_duplicates/remove_duplicates_challenge.ipynb new file mode 100644 index 0000000..fc29abe --- /dev/null +++ b/linked_lists/remove_duplicates/remove_duplicates_challenge.ipynb @@ -0,0 +1,198 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This notebook was prepared by [Donne Martin](http://donnemartin.com). Source and license info is on [GitHub](https://github.com/donnemartin/coding-challenges)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Challenge Notebook" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Problem: Remove duplicates from a linked list\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", + "*Problem statements are sometimes ambiguous. Identifying constraints and stating assumptions can help to ensure you code the intended solution.*\n", + "\n", + "* Is this a singly or doubly linked list?\n", + " * Singly\n", + "* Can you insert NULL values in the list?\n", + " * No\n", + "* Can you use additional data structures?\n", + " * Implement both solutions\n", + "* Can we assume we already have a linked list class that can be used for this problem?\n", + " * Yes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Cases\n", + "\n", + "* Empty linked list -> []\n", + "* One element linked list -> [element]\n", + "* General case with no duplicates\n", + "* General case with duplicates" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Algorithm\n", + "\n", + "Refer to the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/coding-challenges/blob/master/linked_lists/remove_duplicates/remove_duplicates_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 ../linked_list/linked_list.py\n", + "%load ../linked_list/linked_list.py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class MyLinkedList(LinkedList):\n", + " \n", + " def remove_dupes(self):\n", + " # TODO: Implement me\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Unit Test" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + "**The following unit test is expected to fail until you solve the challenge.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# %load test_remove_duplicates.py\n", + "from nose.tools import assert_equal\n", + "\n", + "\n", + "class TestRemoveDupes(object):\n", + " \n", + " def test_remove_dupes(self, linked_list):\n", + " print('Test: Empty list')\n", + " linked_list.remove_dupes()\n", + " assert_equal(linked_list.get_all_data(), [])\n", + "\n", + " print('Test: One element list')\n", + " linked_list.insert_to_front(2)\n", + " linked_list.remove_dupes()\n", + " assert_equal(linked_list.get_all_data(), [2])\n", + "\n", + " print('Test: General case, duplicates')\n", + " linked_list.insert_to_front(1)\n", + " linked_list.insert_to_front(3)\n", + " linked_list.insert_to_front(1)\n", + " linked_list.insert_to_front(1)\n", + " linked_list.remove_dupes()\n", + " assert_equal(linked_list.get_all_data(), [1, 3, 2])\n", + "\n", + " print('Test: General case, no duplicates')\n", + " linked_list.remove_dupes()\n", + " assert_equal(linked_list.get_all_data(), [1, 3, 2])\n", + " \n", + " print('Success: test_remove_dupes\\n')\n", + "\n", + "def main():\n", + " test = TestRemoveDupes()\n", + " linked_list = MyLinkedList(None)\n", + " test.test_remove_dupes(linked_list)\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/coding-challenges/blob/master/linked_lists/remove_duplicates/remove_duplicates_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/linked_lists/remove_duplicates/remove_duplicates_solution.ipynb b/linked_lists/remove_duplicates/remove_duplicates_solution.ipynb index 84764c0..36b4bf7 100644 --- a/linked_lists/remove_duplicates/remove_duplicates_solution.ipynb +++ b/linked_lists/remove_duplicates/remove_duplicates_solution.ipynb @@ -4,7 +4,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This notebook was prepared by [Donne Martin](http://donnemartin.com). Source and license info is on [GitHub](https://bit.ly/code-notes)." + "This notebook was prepared by [Donne Martin](http://donnemartin.com). Source and license info is on [GitHub](https://github.com/donnemartin/coding-challenges)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Solution Notebook" ] }, { @@ -16,9 +23,8 @@ "* [Constraints](#Constraints)\n", "* [Test Cases](#Test-Cases)\n", "* [Algorithm: Hash Map Lookup](#Algorithm:-Hash-Map-Lookup)\n", - "* [Code: Hash Map Lookup](#Code:-Hash-Map-Lookup)\n", "* [Algorithm: In-Place](#Algorithm:-In-Place)\n", - "* [Code: In-Place](#Code:-In-Place)\n", + "* [Code](#Code)\n", "* [Unit Test](#Unit-Test)" ] }, @@ -28,7 +34,7 @@ "source": [ "## Constraints\n", "\n", - "*Problem statements are often intentionally ambiguous. Identifying constraints and stating assumptions can help to ensure you code the intended solution.*\n", + "*Problem statements are sometimes ambiguous. Identifying constraints and stating assumptions can help to ensure you code the intended solution.*\n", "\n", "* Is this a singly or doubly linked list?\n", " * Singly\n", @@ -46,11 +52,10 @@ "source": [ "## Test Cases\n", "\n", - "* Empty linked list\n", - "* One element linked list\n", - "* Multiple elements\n", - "* No duplicates\n", - "* One or more duplicates" + "* Empty linked list -> []\n", + "* One element linked list -> [element]\n", + "* General case with no duplicates\n", + "* General case with duplicates" ] }, { @@ -73,46 +78,6 @@ "* Deletion requires two pointers, one to the previous node and one to the current node" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Code: Hash Map Lookup" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "%run linked_list.py" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "class MyLinkedList(LinkedList):\n", - " def remove_dupes(self):\n", - " seen_data = set()\n", - " curr = self.head\n", - " prev = None\n", - " while curr is not None:\n", - " if curr.data in seen_data:\n", - " prev.next = curr.next\n", - " else:\n", - " seen_data.add(curr.data)\n", - " prev = curr\n", - " curr = curr.next" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -139,19 +104,43 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Code: In-Place" + "## Code" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%run ../linked_list/linked_list.py" + ] + }, + { + "cell_type": "code", + "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [], "source": [ - "class MyLinkedListAlt(LinkedList):\n", + "class MyLinkedList(LinkedList):\n", + " \n", " def remove_dupes(self):\n", + " seen_data = set()\n", + " curr = self.head\n", + " prev = None\n", + " while curr is not None:\n", + " if curr.data in seen_data:\n", + " prev.next = curr.next\n", + " else:\n", + " seen_data.add(curr.data)\n", + " prev = curr\n", + " curr = curr.next\n", + " \n", + " def remove_dupes_in_place(self):\n", " curr = self.head\n", " while curr is not None:\n", " runner = curr\n", @@ -170,16 +159,9 @@ "## Unit Test" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "*It is important to identify and run through general and edge cases from the [Test Cases](#Test-Cases) section by hand. You generally will not be asked to write a unit test like what is shown below.*" - ] - }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": { "collapsed": false }, @@ -188,25 +170,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "Test: Empty list\n", - "Test: One element list\n", - "Test: General case, duplicates\n", - "Test: General case, no duplicates\n", - "Success: test_remove_dupes\n", - "\n", - "Test: Empty list\n", - "Test: One element list\n", - "Test: General case, duplicates\n", - "Test: General case, no duplicates\n", - "Success: test_remove_dupes\n", - "\n" + "Overwriting test_remove_duplicates.py\n" ] } ], "source": [ + "%%writefile test_remove_duplicates.py\n", "from nose.tools import assert_equal\n", "\n", - "class Test(object):\n", + "\n", + "class TestRemoveDupes(object):\n", + " \n", " def test_remove_dupes(self, linked_list):\n", " print('Test: Empty list')\n", " linked_list.remove_dupes()\n", @@ -231,12 +205,37 @@ " \n", " print('Success: test_remove_dupes\\n')\n", "\n", - "if __name__ == '__main__':\n", - " test = Test()\n", + "def main():\n", + " test = TestRemoveDupes()\n", " linked_list = MyLinkedList(None)\n", " test.test_remove_dupes(linked_list)\n", - " linked_list_alt = MyLinkedListAlt(None)\n", - " test.test_remove_dupes(linked_list_alt)" + " \n", + "if __name__ == '__main__':\n", + " main()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Test: Empty list\n", + "Test: One element list\n", + "Test: General case, duplicates\n", + "Test: General case, no duplicates\n", + "Success: test_remove_dupes\n", + "\n" + ] + } + ], + "source": [ + "run -i test_remove_duplicates.py" ] } ], diff --git a/linked_lists/remove_duplicates/test_remove_duplicates.py b/linked_lists/remove_duplicates/test_remove_duplicates.py new file mode 100644 index 0000000..33344d1 --- /dev/null +++ b/linked_lists/remove_duplicates/test_remove_duplicates.py @@ -0,0 +1,36 @@ +from nose.tools import assert_equal + + +class TestRemoveDupes(object): + + def test_remove_dupes(self, linked_list): + print('Test: Empty list') + linked_list.remove_dupes() + assert_equal(linked_list.get_all_data(), []) + + print('Test: One element list') + linked_list.insert_to_front(2) + linked_list.remove_dupes() + assert_equal(linked_list.get_all_data(), [2]) + + print('Test: General case, duplicates') + linked_list.insert_to_front(1) + linked_list.insert_to_front(3) + linked_list.insert_to_front(1) + linked_list.insert_to_front(1) + linked_list.remove_dupes() + assert_equal(linked_list.get_all_data(), [1, 3, 2]) + + print('Test: General case, no duplicates') + linked_list.remove_dupes() + assert_equal(linked_list.get_all_data(), [1, 3, 2]) + + print('Success: test_remove_dupes\n') + +def main(): + test = TestRemoveDupes() + linked_list = MyLinkedList(None) + test.test_remove_dupes(linked_list) + +if __name__ == '__main__': + main() \ No newline at end of file