diff --git a/sorting_searching/new_int/__init__.py b/sorting_searching/new_int/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sorting_searching/new_int/new_int_challenge.ipynb b/sorting_searching/new_int/new_int_challenge.ipynb new file mode 100644 index 0000000..31fb42f --- /dev/null +++ b/sorting_searching/new_int/new_int_challenge.ipynb @@ -0,0 +1,174 @@ +{ + "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: Given an array of 32 integers, find an int not in the input. Use a minimal amount of memory.\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", + "* Are we working with non-negative ints?\n", + " * Yes\n", + "* What is the range of the integers?\n", + " * Discuss the approach for 4 billion integers\n", + " * Implement for 32 integers\n", + "* Can we assume the inputs are valid?\n", + " * No" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Cases\n", + "\n", + "* None -> Exception\n", + "* [] -> Exception\n", + "* General case\n", + " * There is an int excluded from the input -> int\n", + " * There isn't an int excluded from the input -> None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Algorithm\n", + "\n", + "Refer to the [Solution Notebook](). 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": false + }, + "outputs": [], + "source": [ + "from bitstring import BitArray # run pip install bitstring\n", + "\n", + "\n", + "class Bits(object):\n", + "\n", + " def new_int(self, array, max_size):\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": false + }, + "outputs": [], + "source": [ + "# %load test_new_int.py\n", + "from nose.tools import assert_equal, assert_raises\n", + "\n", + "\n", + "class TestBits(object):\n", + "\n", + " def test_new_int(self):\n", + " bits = Bits()\n", + " max_size = 32\n", + " assert_raises(TypeError, bits.new_int, None, max_size)\n", + " assert_raises(TypeError, bits.new_int, [], max_size)\n", + " data = [item for item in range(30)]\n", + " data.append(31)\n", + " assert_equal(bits.new_int(data, max_size), 30)\n", + " data = [item for item in range(32)]\n", + " assert_equal(bits.new_int(data, max_size), None)\n", + " print('Success: test_find_int_excluded_from_input')\n", + "\n", + "\n", + "def main():\n", + " test = TestBits()\n", + " test.test_new_int()\n", + "\n", + "\n", + "if __name__ == '__main__':\n", + " main()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solution Notebook\n", + "\n", + "Review the [Solution Notebook]() for a discussion on algorithms and code solutions." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.4.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/sorting_searching/new_int/new_int_solution.ipynb b/sorting_searching/new_int/new_int_solution.ipynb new file mode 100644 index 0000000..0832aa1 --- /dev/null +++ b/sorting_searching/new_int/new_int_solution.ipynb @@ -0,0 +1,214 @@ +{ + "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: Given an array of n integers, find an int not in the input. Use a minimal amount of memory.\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", + "* Are we working with non-negative ints?\n", + " * Yes\n", + "* What is the range of the integers?\n", + " * Discuss the approach for 4 billion integers\n", + " * Implement for 32 integers\n", + "* Can we assume the inputs are valid?\n", + " * No" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Cases\n", + "\n", + "* None -> Exception\n", + "* [] -> Exception\n", + "* General case\n", + " * There is an int excluded from the input -> int\n", + " * There isn't an int excluded from the input -> None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Algorithm\n", + "\n", + "The problem states to use a minimal amount of memory. We'll use a bit vector to keep track of the inputs.\n", + "\n", + "Say we are given 4 billion integers, which is 2^32 integers. The number of non-negative integers would be 2^31. With a bit vector, we'll need 4 billion bits to map each integer to a bit. Say we had only 1 GB of memory or 2^32 bytes. This would leave us with 8 billion bits.\n", + "\n", + "To simplify this exercise, we'll work with an input of up to 32 ints that we'll map to a bit vector of 32 bits.\n", + "\n", + "
\n", + "\n", + "input = [0, 1, 2, 3, 4...28, 29, 31]\n", + "\n", + "bytes [ 1 ] [ 2 ] [ 3 ] [ 4 ]\n", + "index = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31\n", + "bit_vector = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1\n", + "\n", + "result = 30\n", + "\n", + "* Loop through each item in the input, setting bit_vector[item] = True.\n", + "* Loop through the bit_vector, return the first index where bit_vector[item] == False.\n", + "\n", + "\n", + "\n", + "Complexity:\n", + "* Time: O(b), where b is the number of bits\n", + "* Space: O(b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from bitstring import BitArray # Run pip install bitstring\n", + "\n", + "\n", + "class Bits(object):\n", + "\n", + " def new_int(self, array, max_size):\n", + " if not array:\n", + " raise TypeError('array cannot be None or empty')\n", + " bit_vector = BitArray(max_size)\n", + " for item in array:\n", + " bit_vector[item] = True\n", + " for index, item in enumerate(bit_vector):\n", + " if not item:\n", + " return index\n", + " return None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Unit Test" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting test_new_int.py\n" + ] + } + ], + "source": [ + "%%writefile test_new_int.py\n", + "from nose.tools import assert_equal, assert_raises\n", + "\n", + "\n", + "class TestBits(object):\n", + "\n", + " def test_new_int(self):\n", + " bits = Bits()\n", + " max_size = 32\n", + " assert_raises(TypeError, bits.new_int, None, max_size)\n", + " assert_raises(TypeError, bits.new_int, [], max_size)\n", + " data = [item for item in range(30)]\n", + " data.append(31)\n", + " assert_equal(bits.new_int(data, max_size), 30)\n", + " data = [item for item in range(32)]\n", + " assert_equal(bits.new_int(data, max_size), None)\n", + " print('Success: test_find_int_excluded_from_input')\n", + "\n", + "\n", + "def main():\n", + " test = TestBits()\n", + " test.test_new_int()\n", + "\n", + "\n", + "if __name__ == '__main__':\n", + " main()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Success: test_find_int_excluded_from_input\n" + ] + } + ], + "source": [ + "%run -i test_new_int.py" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.4.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/sorting_searching/new_int/test_new_int.py b/sorting_searching/new_int/test_new_int.py new file mode 100644 index 0000000..39c0eda --- /dev/null +++ b/sorting_searching/new_int/test_new_int.py @@ -0,0 +1,25 @@ +from nose.tools import assert_equal, assert_raises + + +class TestBits(object): + + def test_new_int(self): + bits = Bits() + max_size = 32 + assert_raises(TypeError, bits.new_int, None, max_size) + assert_raises(TypeError, bits.new_int, [], max_size) + data = [item for item in range(30)] + data.append(31) + assert_equal(bits.new_int(data, max_size), 30) + data = [item for item in range(32)] + assert_equal(bits.new_int(data, max_size), None) + print('Success: test_find_int_excluded_from_input') + + +def main(): + test = TestBits() + test.test_new_int() + + +if __name__ == '__main__': + main() \ No newline at end of file