{ "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: Find the highest product of three numbers in a list.\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 the input a list of integers?\n", " * Yes\n", "* Can we get negative inputs?\n", " * Yes\n", "* Can there be duplicate entries in the input?\n", " * Yes\n", "* Will there always be at least three integers?\n", " * No\n", "* Can we assume the inputs are valid?\n", " * No, check for None input\n", "* Can we assume this fits memory?\n", " * Yes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Test Cases\n", "\n", "* None -> TypeError\n", "* Less than three ints -> ValueError\n", "* [5, -2, 3] -> -30\n", "* [5, -2, 3, 1, -1, 4] -> 60" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Algorithm\n", "\n", "### Brute force:\n", "\n", "Use three loops and multiple each numbers.\n", "\n", "Complexity:\n", "* Time: O(n^3)\n", "* Space: O(1)\n", "\n", "### Sorting:\n", "\n", "Sort the list, multiply the last three elements.\n", "\n", "Complexity:\n", "* Time: O(n log(n))\n", "* Space: O(1)\n", "\n", "### Greedy:\n", "\n", "
\n",
    " 0   1  2  3   4  5\n",
    "[5, -2, 3, 1, -1, 4] -> 60\n",
    "\n",
    "max_prod_of_three = -30\n",
    "max_prod_of_two = -10\n",
    "max_num = 5\n",
    "min_prod_of_two = -10\n",
    "min_num = -2\n",
    "\n",
    " 0   1  2  3   4  5\n",
    "[5, -2, 3, 1, -1, 4] -> 60\n",
    "        ^\n",
    "max_prod_of_three = -30\n",
    "max_prod_of_two = 15\n",
    "max_num = 5\n",
    "min_prod_of_two = -10\n",
    "min_num = -2\n",
    "\n",
    " 0   1  2  3   4  5\n",
    "[5, -2, 3, 1, -1, 4] -> 60\n",
    "           ^\n",
    "max_prod_of_three = 15\n",
    "max_prod_of_two = 15\n",
    "max_num = 5\n",
    "min_prod_of_two = -10\n",
    "min_num = -2\n",
    "\n",
    " 0   1  2  3   4  5\n",
    "[5, -2, 3, 1, -1, 4] -> 60\n",
    "               ^\n",
    "max_prod_of_three = 15\n",
    "max_prod_of_two = 15\n",
    "max_num = 5\n",
    "min_prod_of_two = -10\n",
    "min_num = -2\n",
    "\n",
    " 0   1  2  3   4  5\n",
    "[5, -2, 3, 1, -1, 4] -> 60\n",
    "                  ^\n",
    "max_prod_of_three = 60\n",
    "max_prod_of_two = 15\n",
    "max_num = 5\n",
    "min_prod_of_two = -10\n",
    "min_num = -2\n",
    "
\n", "\n", "Complexity:\n", "* Time: O(n)\n", "* Space: O(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Code" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "class Solution(object):\n", "\n", " def max_prod_three_nlogn(self, array):\n", " if array is None:\n", " raise TypeError('array cannot be None')\n", " if len(array) < 3:\n", " raise ValueError('array must have 3 or more ints')\n", " array.sort()\n", " product = 1\n", " for item in array[-3:]:\n", " product *= item\n", " return product\n", "\n", " def max_prod_three(self, array):\n", " if array is None:\n", " raise TypeError('array cannot be None')\n", " if len(array) < 3:\n", " raise ValueError('array must have 3 or more ints')\n", " curr_max_prod_three = array[0] * array[1] * array[2]\n", " max_prod_two = array[0] * array[1]\n", " min_prod_two = array[0] * array[1]\n", " max_num = max(array[0], array[1])\n", " min_num = min(array[0], array[1])\n", " for i in range(2, len(array)):\n", " curr_max_prod_three = max(curr_max_prod_three,\n", " max_prod_two * array[i],\n", " min_prod_two * array[i])\n", " max_prod_two = max(max_prod_two,\n", " max_num * array[i],\n", " min_num * array[i])\n", " min_prod_two = min(min_prod_two,\n", " max_num * array[i],\n", " min_num * array[i])\n", " max_num = max(max_num, array[i])\n", " min_num = min(min_num, array[i])\n", " return curr_max_prod_three" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Unit Test" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Overwriting test_prod_three.py\n" ] } ], "source": [ "%%writefile test_prod_three.py\n", "import unittest\n", "\n", "\n", "class TestProdThree(unittest.TestCase):\n", "\n", " def test_prod_three(self):\n", " solution = Solution()\n", " self.assertRaises(TypeError, solution.max_prod_three, None)\n", " self.assertRaises(ValueError, solution.max_prod_three, [1, 2])\n", " self.assertEqual(solution.max_prod_three([5, -2, 3]), -30)\n", " self.assertEqual(solution.max_prod_three([5, -2, 3, 1, -1, 4]), 60)\n", " print('Success: test_prod_three')\n", "\n", "\n", "def main():\n", " test = TestProdThree()\n", " test.test_prod_three()\n", "\n", "\n", "if __name__ == '__main__':\n", " main()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Success: test_prod_three\n" ] } ], "source": [ "%run -i test_prod_three.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.7.2" } }, "nbformat": 4, "nbformat_minor": 1 }