diff --git a/math_probability/math_ops/__init__.py b/math_probability/math_ops/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/math_probability/math_ops/math_ops_challenge.ipynb b/math_probability/math_ops/math_ops_challenge.ipynb new file mode 100644 index 0000000..bcd19d4 --- /dev/null +++ b/math_probability/math_ops/math_ops_challenge.ipynb @@ -0,0 +1,190 @@ +{ + "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 class with an insert method to insert an int to a list. It should also support calculating the max, min, mean, and mode in O(1).\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", + "* Can we assume the inputs are valid?\n", + " * No\n", + "* Is there a range of inputs?\n", + " * 0 <= item <= 100\n", + "* Should mean return a float?\n", + " * Yes\n", + "* Should the other results return an int?\n", + " * Yes\n", + "* If there are multiple modes, what do we return?\n", + " * Any of the modes\n", + "* Can we assume this fits memory?\n", + " * Yes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Cases\n", + "\n", + "* None -> TypeError\n", + "* [] -> ValueError\n", + "* [5, 2, 7, 9, 9, 2, 9, 4, 3, 3, 2]\n", + " * max: 9\n", + " * min: 2\n", + " * mean: 55\n", + " * mode: 9 or 2" + ] + }, + { + "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": [ + "class Solution(object):\n", + "\n", + " def __init__(self, upper_limit=100):\n", + " # TODO: Implement me\n", + " pass\n", + "\n", + " def insert(self, val):\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_math_ops.py\n", + "from nose.tools import assert_equal, assert_true, assert_raises\n", + "\n", + "\n", + "class TestMathOps(object):\n", + "\n", + " def test_math_ops(self):\n", + " solution = Solution()\n", + " assert_raises(TypeError, solution.insert, None)\n", + " solution.insert(5)\n", + " solution.insert(2)\n", + " solution.insert(7)\n", + " solution.insert(9)\n", + " solution.insert(9)\n", + " solution.insert(2)\n", + " solution.insert(9)\n", + " solution.insert(4)\n", + " solution.insert(3)\n", + " solution.insert(3)\n", + " solution.insert(2)\n", + " assert_equal(solution.max, 9)\n", + " assert_equal(solution.min, 2)\n", + " assert_equal(solution.mean, 5)\n", + " assert_true(solution.mode in (2, 92))\n", + " print('Success: test_math_ops')\n", + "\n", + "\n", + "def main():\n", + " test = TestMathOps()\n", + " test.test_math_ops()\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.5.0" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/math_probability/math_ops/math_ops_solution.ipynb b/math_probability/math_ops/math_ops_solution.ipynb new file mode 100644 index 0000000..8569371 --- /dev/null +++ b/math_probability/math_ops/math_ops_solution.ipynb @@ -0,0 +1,236 @@ +{ + "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 class with an insert method to insert an int to a list. It should also support calculating the max, min, mean, and mode in O(1).\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", + "* Can we assume the inputs are valid?\n", + " * No\n", + "* Is there a range of inputs?\n", + " * 0 <= item <= 100\n", + "* Should mean return a float?\n", + " * Yes\n", + "* Should the other results return an int?\n", + " * Yes\n", + "* If there are multiple modes, what do we return?\n", + " * Any of the modes\n", + "* Can we assume this fits memory?\n", + " * Yes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Cases\n", + "\n", + "* None -> TypeError\n", + "* [] -> ValueError\n", + "* [5, 2, 7, 9, 9, 2, 9, 4, 3, 3, 2]\n", + " * max: 9\n", + " * min: 2\n", + " * mean: 55\n", + " * mode: 9 or 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Algorithm\n", + "\n", + "* We'll init our max and min to None. Alternatively, we can init them to -sys.maxsize and sys.maxsize, respectively.\n", + "* For mean, we'll keep track of the number of items we have inserted so far, as well as the running sum.\n", + "* For mode, we'll keep track of the current mode and an array with the size of the given upper limit\n", + " * Each element in the array will be init to 0\n", + " * Each time we insert, we'll increment the element corresponding to the inserted item's value\n", + "* On each insert:\n", + " * Update the max and min\n", + " * Update the mean by calculating running_sum / num_items\n", + " * Update the mode by comparing the mode array's value with the current mode\n", + "\n", + "Complexity:\n", + "* Time: O(1)\n", + "* Space: O(1), we are treating the 101 element array as a constant O(1), we could also see this as O(k)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from __future__ import division\n", + "\n", + "\n", + "class Solution(object):\n", + "\n", + " def __init__(self, upper_limit=100):\n", + " self.max = None\n", + " self.min = None\n", + " # Mean\n", + " self.num_items = 0\n", + " self.running_sum = 0\n", + " self.mean = None\n", + " # Mode\n", + " self.array = [0] * (upper_limit + 1)\n", + " self.mode_ocurrences = 0\n", + " self.mode = None\n", + "\n", + " def insert(self, val):\n", + " if val is None:\n", + " raise TypeError('val cannot be None')\n", + " if self.max is None or val > self.max:\n", + " self.max = val\n", + " if self.min is None or val < self.min:\n", + " self.min = val\n", + " # Calculate the mean\n", + " self.num_items += 1\n", + " self.running_sum += val\n", + " self.mean = self.running_sum / self.num_items\n", + " # Calculate the mode\n", + " self.array[val] += 1\n", + " if self.array[val] > self.mode_ocurrences:\n", + " self.mode_ocurrences = self.array[val]\n", + " self.mode = val" + ] + }, + { + "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_math_ops.py\n" + ] + } + ], + "source": [ + "%%writefile test_math_ops.py\n", + "from nose.tools import assert_equal, assert_true, assert_raises\n", + "\n", + "\n", + "class TestMathOps(object):\n", + "\n", + " def test_math_ops(self):\n", + " solution = Solution()\n", + " assert_raises(TypeError, solution.insert, None)\n", + " solution.insert(5)\n", + " solution.insert(2)\n", + " solution.insert(7)\n", + " solution.insert(9)\n", + " solution.insert(9)\n", + " solution.insert(2)\n", + " solution.insert(9)\n", + " solution.insert(4)\n", + " solution.insert(3)\n", + " solution.insert(3)\n", + " solution.insert(2)\n", + " assert_equal(solution.max, 9)\n", + " assert_equal(solution.min, 2)\n", + " assert_equal(solution.mean, 5)\n", + " assert_true(solution.mode in (2, 9))\n", + " print('Success: test_math_ops')\n", + "\n", + "\n", + "def main():\n", + " test = TestMathOps()\n", + " test.test_math_ops()\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_math_ops\n" + ] + } + ], + "source": [ + "%run -i test_math_ops.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.5.0" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/math_probability/math_ops/test_math_ops.py b/math_probability/math_ops/test_math_ops.py new file mode 100644 index 0000000..1e1c18a --- /dev/null +++ b/math_probability/math_ops/test_math_ops.py @@ -0,0 +1,33 @@ +from nose.tools import assert_equal, assert_true, assert_raises + + +class TestMathOps(object): + + def test_math_ops(self): + solution = Solution() + assert_raises(TypeError, solution.insert, None) + solution.insert(5) + solution.insert(2) + solution.insert(7) + solution.insert(9) + solution.insert(9) + solution.insert(2) + solution.insert(9) + solution.insert(4) + solution.insert(3) + solution.insert(3) + solution.insert(2) + assert_equal(solution.max, 9) + assert_equal(solution.min, 2) + assert_equal(solution.mean, 5) + assert_true(solution.mode in (2, 9)) + print('Success: test_math_ops') + + +def main(): + test = TestMathOps() + test.test_math_ops() + + +if __name__ == '__main__': + main() \ No newline at end of file