diff --git a/recursion_dynamic/n_pairs_parentheses/__init__.py b/recursion_dynamic/n_pairs_parentheses/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/recursion_dynamic/n_pairs_parentheses/n_pairs_parentheses_challenge.ipynb b/recursion_dynamic/n_pairs_parentheses/n_pairs_parentheses_challenge.ipynb index ac96f04..f7a3e77 100644 --- a/recursion_dynamic/n_pairs_parentheses/n_pairs_parentheses_challenge.ipynb +++ b/recursion_dynamic/n_pairs_parentheses/n_pairs_parentheses_challenge.ipynb @@ -18,7 +18,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Problem: Print all valid combinations of n-pairs of parentheses.\n", + "## Problem: Find all valid combinations of n-pairs of parentheses.\n", "\n", "* [Constraints](#Constraints)\n", "* [Test Cases](#Test-Cases)\n", @@ -33,7 +33,17 @@ "metadata": {}, "source": [ "## Constraints\n", - "* None" + "\n", + "* Is the input an integer representing the number of pairs?\n", + " * Yes\n", + "* Can we assume the inputs are valid?\n", + " * No\n", + "* Is the output a list of valid combinations?\n", + " * Yes\n", + "* Should the output have duplicates?\n", + " * No\n", + "* Can we assume this fits memory?\n", + " * Yes" ] }, { @@ -42,10 +52,14 @@ "source": [ "## Test Cases\n", "\n", + "
\n", + "* None -> Exception\n", + "* Negative -> Exception\n", "* 0 -> []\n", - "* 1 -> [()]\n", - "* 2 -> [(()), ()()]\n", - "* 3 -> [((())), (()()), (())(), ()(()), ()()()]" + "* 1 -> ['()']\n", + "* 2 -> ['(())', '()()']\n", + "* 3 -> ['((()))', '(()())', '(())()', '()(())', '()()()']\n", + "" ] }, { @@ -72,17 +86,11 @@ }, "outputs": [], "source": [ - "def parentheses_util(no_left, no_right, pair_string, result):\n", - " # TODO: implement parentheses pairing here\n", - " pass\n", + "class Parentheses(object):\n", "\n", - "\n", - "def pair_parentheses(n):\n", - " result_set = set()\n", - " if n == 0:\n", - " return result_set\n", - " parentheses_util(n, n, '', result_set)\n", - " return result_set" + " def find_pair(self, num_pairs):\n", + " # TODO: implement me\n", + " pass" ] }, { @@ -101,27 +109,30 @@ "outputs": [], "source": [ "# %load test_n_pairs_parentheses.py\n", - "from nose.tools import assert_equal\n", + "from nose.tools import assert_equal, assert_raises\n", "\n", "\n", "class TestPairParentheses(object):\n", "\n", - " def test_pair_parentheses(self, solution):\n", - " assert_equal(solution(0), set([]))\n", - " assert_equal(solution(1), set(['()']))\n", - " assert_equal(solution(2), set(['(())', \n", - " '()()']))\n", - " assert_equal(solution(3), set(['((()))', \n", - " '(()())', \n", - " '(())()', \n", - " '()(())', \n", - " '()()()']))\n", + " def test_pair_parentheses(self):\n", + " parentheses = Parentheses()\n", + " assert_raises(TypeError, parentheses.find_pair, None)\n", + " assert_raises(ValueError, parentheses.find_pair, -1)\n", + " assert_equal(parentheses.find_pair(0), [])\n", + " assert_equal(parentheses.find_pair(1), ['()'])\n", + " assert_equal(parentheses.find_pair(2), ['(())',\n", + " '()()'])\n", + " assert_equal(parentheses.find_pair(3), ['((()))',\n", + " '(()())',\n", + " '(())()',\n", + " '()(())',\n", + " '()()()'])\n", " print('Success: test_pair_parentheses')\n", "\n", "\n", "def main():\n", " test = TestPairParentheses()\n", - " test.test_pair_parentheses(pair_parentheses)\n", + " test.test_pair_parentheses()\n", "\n", "\n", "if __name__ == '__main__':\n", @@ -136,34 +147,25 @@ "\n", "Review the [Solution Notebook](http://nbviewer.ipython.org/github/donnemartin/interactive-coding-challenges/blob/master/recursion_dynamic/n_pairs_parentheses/n_pairs_parentheses_solution.ipynb) for a discussion on algorithms and code solutions." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.10" + "pygments_lexer": "ipython3", + "version": "3.5.0" } }, "nbformat": 4, diff --git a/recursion_dynamic/n_pairs_parentheses/n_pairs_parentheses_solution.ipynb b/recursion_dynamic/n_pairs_parentheses/n_pairs_parentheses_solution.ipynb index c7ddd1a..a122861 100644 --- a/recursion_dynamic/n_pairs_parentheses/n_pairs_parentheses_solution.ipynb +++ b/recursion_dynamic/n_pairs_parentheses/n_pairs_parentheses_solution.ipynb @@ -18,7 +18,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Problem: Print all valid combinations of n-pairs of parentheses.\n", + "## Problem: Find all valid combinations of n-pairs of parentheses.\n", "\n", "* [Constraints](#Constraints)\n", "* [Test Cases](#Test-Cases)\n", @@ -32,7 +32,17 @@ "metadata": {}, "source": [ "## Constraints\n", - "* None" + "\n", + "* Is the input an integer representing the number of pairs?\n", + " * Yes\n", + "* Can we assume the inputs are valid?\n", + " * No\n", + "* Is the output a list of valid combinations?\n", + " * Yes\n", + "* Should the output have duplicates?\n", + " * No\n", + "* Can we assume this fits memory?\n", + " * Yes" ] }, { @@ -41,10 +51,14 @@ "source": [ "## Test Cases\n", "\n", - "* 0 -> ' '\n", - "* 1 -> ()\n", - "* 2 -> (()), ()()\n", - "* 3 -> ((())), (()()), (())(), ()(()), ()()()" + "
\n", + "* None -> Exception\n", + "* Negative -> Exception\n", + "* 0 -> []\n", + "* 1 -> ['()']\n", + "* 2 -> ['(())', '()()']\n", + "* 3 -> ['((()))', '(()())', '(())()', '()(())', '()()()']\n", + "" ] }, { @@ -64,14 +78,14 @@ " - Add the string generated to the result set\n", "* Case 1: `l > 0`\n", " - Add a left parenthesis to the parentheses string.\n", - " - Call parentheses_util(l - 1, r, new_string, result_set)\n", + " - Recurse (l - 1, r, new_string, result_set)\n", "* Case 2: `r > l`\n", " - Add a right parenthesis to the parentheses string.\n", - " - Call parentheses_util(l, r - 1, new_string, result_set)\n", + " - Recurse (l, r - 1, new_string, result_set)\n", "\n", "Complexity:\n", - "* Time: `O(4^n/n^(3/2))`. See [Catalan numbers](https://en.wikipedia.org/wiki/Catalan_number#Applications_in_combinatorics)\n", - "* Space complexity: `O(n)` (Due to the implicit call stack storing a maximum of 2n function calls)" + "* Time: `O(4^n/n^(3/2))`, see [Catalan numbers](https://en.wikipedia.org/wiki/Catalan_number#Applications_in_combinatorics) - 1, 1, 2, 5, 14, 42, 132...\n", + "* Space complexity: `O(n)`, due to the implicit call stack storing a maximum of 2n function calls)" ] }, { @@ -89,22 +103,28 @@ }, "outputs": [], "source": [ - "def parentheses_util(no_left, no_right, pair_string, result):\n", - " if no_left == 0 and no_right == 0:\n", - " result.add(pair_string)\n", - " else:\n", - " if no_left > 0:\n", - " parentheses_util(no_left - 1, no_right, pair_string + '(', result)\n", - " if no_right > no_left:\n", - " parentheses_util(no_left, no_right - 1, pair_string + ')', result)\n", + "class Parentheses(object):\n", "\n", + " def find_pair(self, num_pairs):\n", + " if num_pairs is None:\n", + " raise TypeError('num_pairs cannot be None')\n", + " if num_pairs < 0:\n", + " raise ValueError('num_pairs cannot be < 0')\n", + " if not num_pairs:\n", + " return []\n", + " results = []\n", + " curr_results = []\n", + " self._find_pair(num_pairs, num_pairs, curr_results, results)\n", + " return results\n", "\n", - "def pair_parentheses(n):\n", - " result_set = set()\n", - " if n == 0:\n", - " return result_set\n", - " parentheses_util(n, n, '', result_set)\n", - " return result_set" + " def _find_pair(self, nleft, nright, curr_results, results):\n", + " if nleft == 0 and nright == 0:\n", + " results.append(''.join(curr_results))\n", + " else:\n", + " if nleft >= 0:\n", + " self._find_pair(nleft-1, nright, curr_results+['('], results)\n", + " if nright > nleft:\n", + " self._find_pair(nleft, nright-1, curr_results+[')'], results)" ] }, { @@ -131,27 +151,30 @@ ], "source": [ "%%writefile test_n_pairs_parentheses.py\n", - "from nose.tools import assert_equal\n", + "from nose.tools import assert_equal, assert_raises\n", "\n", "\n", "class TestPairParentheses(object):\n", "\n", - " def test_pair_parentheses(self, solution):\n", - " assert_equal(solution(0), set([]))\n", - " assert_equal(solution(1), set(['()']))\n", - " assert_equal(solution(2), set(['(())', \n", - " '()()']))\n", - " assert_equal(solution(3), set(['((()))', \n", - " '(()())', \n", - " '(())()', \n", - " '()(())', \n", - " '()()()']))\n", + " def test_pair_parentheses(self):\n", + " parentheses = Parentheses()\n", + " assert_raises(TypeError, parentheses.find_pair, None)\n", + " assert_raises(ValueError, parentheses.find_pair, -1)\n", + " assert_equal(parentheses.find_pair(0), [])\n", + " assert_equal(parentheses.find_pair(1), ['()'])\n", + " assert_equal(parentheses.find_pair(2), ['(())',\n", + " '()()'])\n", + " assert_equal(parentheses.find_pair(3), ['((()))',\n", + " '(()())',\n", + " '(())()',\n", + " '()(())',\n", + " '()()()'])\n", " print('Success: test_pair_parentheses')\n", "\n", "\n", "def main():\n", " test = TestPairParentheses()\n", - " test.test_pair_parentheses(pair_parentheses)\n", + " test.test_pair_parentheses()\n", "\n", "\n", "if __name__ == '__main__':\n", @@ -180,21 +203,21 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 2", + "display_name": "Python 3", "language": "python", - "name": "python2" + "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 2 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.10" + "pygments_lexer": "ipython3", + "version": "3.5.0" } }, "nbformat": 4, diff --git a/recursion_dynamic/n_pairs_parentheses/test_n_pairs_parentheses.py b/recursion_dynamic/n_pairs_parentheses/test_n_pairs_parentheses.py index 1b735e8..8c2ab34 100644 --- a/recursion_dynamic/n_pairs_parentheses/test_n_pairs_parentheses.py +++ b/recursion_dynamic/n_pairs_parentheses/test_n_pairs_parentheses.py @@ -1,24 +1,27 @@ -from nose.tools import assert_equal +from nose.tools import assert_equal, assert_raises class TestPairParentheses(object): - def test_pair_parentheses(self, solution): - assert_equal(solution(0), set([])) - assert_equal(solution(1), set(['()'])) - assert_equal(solution(2), set(['(())', - '()()'])) - assert_equal(solution(3), set(['((()))', - '(()())', - '(())()', - '()(())', - '()()()'])) + def test_pair_parentheses(self): + parentheses = Parentheses() + assert_raises(TypeError, parentheses.find_pair, None) + assert_raises(ValueError, parentheses.find_pair, -1) + assert_equal(parentheses.find_pair(0), []) + assert_equal(parentheses.find_pair(1), ['()']) + assert_equal(parentheses.find_pair(2), ['(())', + '()()']) + assert_equal(parentheses.find_pair(3), ['((()))', + '(()())', + '(())()', + '()(())', + '()()()']) print('Success: test_pair_parentheses') def main(): test = TestPairParentheses() - test.test_pair_parentheses(pair_parentheses) + test.test_pair_parentheses() if __name__ == '__main__':