#!/usr/bin/env python # coding: utf-8 # 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). # # Solution Notebook # ## Problem: Find the highest product of three numbers in a list. # # * [Constraints](#Constraints) # * [Test Cases](#Test-Cases) # * [Algorithm](#Algorithm) # * [Code](#Code) # * [Unit Test](#Unit-Test) # ## Constraints # # * Is the input a list of integers? # * Yes # * Can we get negative inputs? # * Yes # * Can there be duplicate entries in the input? # * Yes # * Will there always be at least three integers? # * No # * Can we assume the inputs are valid? # * No, check for None input # * Can we assume this fits memory? # * Yes # ## Test Cases # # * None -> TypeError # * Less than three ints -> ValueError # * [5, -2, 3] -> -30 # * [5, -2, 3, 1, -1, 4] -> 60 # ## Algorithm # # ### Brute force: # # Use three loops and multiple each numbers. # # Complexity: # * Time: O(n^3) # * Space: O(1) # # ### Sorting: # # Sort the list, multiply the last three elements. # # Complexity: # * Time: O(n log(n)) # * Space: O(1) # # ### Greedy: # #
# 0 1 2 3 4 5 # [5, -2, 3, 1, -1, 4] -> 60 # # max_prod_of_three = -30 # max_prod_of_two = -10 # max_num = 5 # min_prod_of_two = -10 # min_num = -2 # # 0 1 2 3 4 5 # [5, -2, 3, 1, -1, 4] -> 60 # ^ # max_prod_of_three = -30 # max_prod_of_two = 15 # max_num = 5 # min_prod_of_two = -10 # min_num = -2 # # 0 1 2 3 4 5 # [5, -2, 3, 1, -1, 4] -> 60 # ^ # max_prod_of_three = 15 # max_prod_of_two = 15 # max_num = 5 # min_prod_of_two = -10 # min_num = -2 # # 0 1 2 3 4 5 # [5, -2, 3, 1, -1, 4] -> 60 # ^ # max_prod_of_three = 15 # max_prod_of_two = 15 # max_num = 5 # min_prod_of_two = -10 # min_num = -2 # # 0 1 2 3 4 5 # [5, -2, 3, 1, -1, 4] -> 60 # ^ # max_prod_of_three = 60 # max_prod_of_two = 15 # max_num = 5 # min_prod_of_two = -10 # min_num = -2 ## # Complexity: # * Time: O(n) # * Space: O(1) # ## Code # In[1]: class Solution(object): def max_prod_three_nlogn(self, array): if array is None: raise TypeError('array cannot be None') if len(array) < 3: raise ValueError('array must have 3 or more ints') array.sort() product = 1 for item in array[-3:]: product *= item return product def max_prod_three(self, array): if array is None: raise TypeError('array cannot be None') if len(array) < 3: raise ValueError('array must have 3 or more ints') curr_max_prod_three = array[0] * array[1] * array[2] max_prod_two = array[0] * array[1] min_prod_two = array[0] * array[1] max_num = max(array[0], array[1]) min_num = min(array[0], array[1]) for i in range(2, len(array)): curr_max_prod_three = max(curr_max_prod_three, max_prod_two * array[i], min_prod_two * array[i]) max_prod_two = max(max_prod_two, max_num * array[i], min_num * array[i]) min_prod_two = min(min_prod_two, max_num * array[i], min_num * array[i]) max_num = max(max_num, array[i]) min_num = min(min_num, array[i]) return curr_max_prod_three # ## Unit Test # In[2]: get_ipython().run_cell_magic('writefile', 'test_prod_three.py', "import unittest\n\n\nclass 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\ndef main():\n test = TestProdThree()\n test.test_prod_three()\n\n\nif __name__ == '__main__':\n main()\n") # In[3]: get_ipython().run_line_magic('run', '-i test_prod_three.py')