Insect combinatorics challenge












1














Below is the problem taken from Berkeley's Cs61A page here




Question 9: Insect Combinatorics*



Consider an insect in an M by N grid. The insect starts at the bottom left corner, (0, 0), and wants to end up at the top right corner, (M-1, N-1). The insect is only capable of moving right or up. Write a function paths that takes a grid length and width and returns the number of different paths the insect can take from the start to the goal. (There is a closed-form solution to this problem, but try to answer it procedurally using recursion.)
enter image description here



For example, the 2 by 2 grid has a total of two ways for the insect to move from the start to the goal. For the 3 by 3 grid, the insect has 6 diferent paths (only 3 are shown above).



def paths(m, n):
"""Return the number of paths from one corner of an
M by N grid to the opposite corner.

>>> paths(2, 2)
2
>>> paths(5, 7)
210
>>> paths(117, 1)
1
>>> paths(1, 157)
1
"""
"*** YOUR CODE HERE ***"



This solution is with the knowledge of 'higher order function' and 'recursion'. I've yet to learn data structures and algorithms (if required).



Idea: Started from the destination and found the possibilities. As per the skill level, the solution took 3 hours of my time. Please provide feedback on this.



def paths(m, n):
"""Return the number of paths from one corner of an
M by N grid to the opposite corner.

>>> paths(2, 2)
2
>>> paths(5, 7)
210
>>> paths(117, 1)
1
>>> paths(1, 157)
1
"""
count_paths = 0
def find_number_of_paths(x, y):
if x == 0 and y == 0:
nonlocal count_paths
count_paths += 1
return
if x > 0:
find_number_of_paths(x-1, y)
if y > 0:
find_number_of_paths(x, y-1)
find_number_of_paths(m-1, n-1)
return count_paths



  1. Can we avoid re-assignment operator on count_paths?

  2. Can we avoid nested function definitions?

  3. Is there a name for above solution approach in algorithm world? Any better approach?


Note: As per this assignment, no usage of data model is recommended.










share|improve this question





























    1














    Below is the problem taken from Berkeley's Cs61A page here




    Question 9: Insect Combinatorics*



    Consider an insect in an M by N grid. The insect starts at the bottom left corner, (0, 0), and wants to end up at the top right corner, (M-1, N-1). The insect is only capable of moving right or up. Write a function paths that takes a grid length and width and returns the number of different paths the insect can take from the start to the goal. (There is a closed-form solution to this problem, but try to answer it procedurally using recursion.)
    enter image description here



    For example, the 2 by 2 grid has a total of two ways for the insect to move from the start to the goal. For the 3 by 3 grid, the insect has 6 diferent paths (only 3 are shown above).



    def paths(m, n):
    """Return the number of paths from one corner of an
    M by N grid to the opposite corner.

    >>> paths(2, 2)
    2
    >>> paths(5, 7)
    210
    >>> paths(117, 1)
    1
    >>> paths(1, 157)
    1
    """
    "*** YOUR CODE HERE ***"



    This solution is with the knowledge of 'higher order function' and 'recursion'. I've yet to learn data structures and algorithms (if required).



    Idea: Started from the destination and found the possibilities. As per the skill level, the solution took 3 hours of my time. Please provide feedback on this.



    def paths(m, n):
    """Return the number of paths from one corner of an
    M by N grid to the opposite corner.

    >>> paths(2, 2)
    2
    >>> paths(5, 7)
    210
    >>> paths(117, 1)
    1
    >>> paths(1, 157)
    1
    """
    count_paths = 0
    def find_number_of_paths(x, y):
    if x == 0 and y == 0:
    nonlocal count_paths
    count_paths += 1
    return
    if x > 0:
    find_number_of_paths(x-1, y)
    if y > 0:
    find_number_of_paths(x, y-1)
    find_number_of_paths(m-1, n-1)
    return count_paths



    1. Can we avoid re-assignment operator on count_paths?

    2. Can we avoid nested function definitions?

    3. Is there a name for above solution approach in algorithm world? Any better approach?


    Note: As per this assignment, no usage of data model is recommended.










    share|improve this question



























      1












      1








      1


      1





      Below is the problem taken from Berkeley's Cs61A page here




      Question 9: Insect Combinatorics*



      Consider an insect in an M by N grid. The insect starts at the bottom left corner, (0, 0), and wants to end up at the top right corner, (M-1, N-1). The insect is only capable of moving right or up. Write a function paths that takes a grid length and width and returns the number of different paths the insect can take from the start to the goal. (There is a closed-form solution to this problem, but try to answer it procedurally using recursion.)
      enter image description here



      For example, the 2 by 2 grid has a total of two ways for the insect to move from the start to the goal. For the 3 by 3 grid, the insect has 6 diferent paths (only 3 are shown above).



      def paths(m, n):
      """Return the number of paths from one corner of an
      M by N grid to the opposite corner.

      >>> paths(2, 2)
      2
      >>> paths(5, 7)
      210
      >>> paths(117, 1)
      1
      >>> paths(1, 157)
      1
      """
      "*** YOUR CODE HERE ***"



      This solution is with the knowledge of 'higher order function' and 'recursion'. I've yet to learn data structures and algorithms (if required).



      Idea: Started from the destination and found the possibilities. As per the skill level, the solution took 3 hours of my time. Please provide feedback on this.



      def paths(m, n):
      """Return the number of paths from one corner of an
      M by N grid to the opposite corner.

      >>> paths(2, 2)
      2
      >>> paths(5, 7)
      210
      >>> paths(117, 1)
      1
      >>> paths(1, 157)
      1
      """
      count_paths = 0
      def find_number_of_paths(x, y):
      if x == 0 and y == 0:
      nonlocal count_paths
      count_paths += 1
      return
      if x > 0:
      find_number_of_paths(x-1, y)
      if y > 0:
      find_number_of_paths(x, y-1)
      find_number_of_paths(m-1, n-1)
      return count_paths



      1. Can we avoid re-assignment operator on count_paths?

      2. Can we avoid nested function definitions?

      3. Is there a name for above solution approach in algorithm world? Any better approach?


      Note: As per this assignment, no usage of data model is recommended.










      share|improve this question















      Below is the problem taken from Berkeley's Cs61A page here




      Question 9: Insect Combinatorics*



      Consider an insect in an M by N grid. The insect starts at the bottom left corner, (0, 0), and wants to end up at the top right corner, (M-1, N-1). The insect is only capable of moving right or up. Write a function paths that takes a grid length and width and returns the number of different paths the insect can take from the start to the goal. (There is a closed-form solution to this problem, but try to answer it procedurally using recursion.)
      enter image description here



      For example, the 2 by 2 grid has a total of two ways for the insect to move from the start to the goal. For the 3 by 3 grid, the insect has 6 diferent paths (only 3 are shown above).



      def paths(m, n):
      """Return the number of paths from one corner of an
      M by N grid to the opposite corner.

      >>> paths(2, 2)
      2
      >>> paths(5, 7)
      210
      >>> paths(117, 1)
      1
      >>> paths(1, 157)
      1
      """
      "*** YOUR CODE HERE ***"



      This solution is with the knowledge of 'higher order function' and 'recursion'. I've yet to learn data structures and algorithms (if required).



      Idea: Started from the destination and found the possibilities. As per the skill level, the solution took 3 hours of my time. Please provide feedback on this.



      def paths(m, n):
      """Return the number of paths from one corner of an
      M by N grid to the opposite corner.

      >>> paths(2, 2)
      2
      >>> paths(5, 7)
      210
      >>> paths(117, 1)
      1
      >>> paths(1, 157)
      1
      """
      count_paths = 0
      def find_number_of_paths(x, y):
      if x == 0 and y == 0:
      nonlocal count_paths
      count_paths += 1
      return
      if x > 0:
      find_number_of_paths(x-1, y)
      if y > 0:
      find_number_of_paths(x, y-1)
      find_number_of_paths(m-1, n-1)
      return count_paths



      1. Can we avoid re-assignment operator on count_paths?

      2. Can we avoid nested function definitions?

      3. Is there a name for above solution approach in algorithm world? Any better approach?


      Note: As per this assignment, no usage of data model is recommended.







      python python-3.x recursion homework combinatorics






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Apr 2 '18 at 22:31









      Grant Miller

      2232416




      2232416










      asked Jun 30 '15 at 9:44









      overexchangeoverexchange

      1,59852347




      1,59852347






















          1 Answer
          1






          active

          oldest

          votes


















          5














          Using nonlocal rather than global is certainly good, but better yet would be returning values.



          def paths(m, n):
          def find_number_of_paths(x, y):
          if x == 0 and y == 0:
          return 1

          ret = 0

          if x > 0:
          ret += find_number_of_paths(x-1, y)

          if y > 0:
          ret += find_number_of_paths(x, y-1)

          return ret

          return find_number_of_paths(m-1, n-1)


          That lets us elide the outer function entirely:



          def paths(x, y):
          if x == 1 and y == 1:
          return 1

          ret = 0

          if x > 1:
          ret += paths(x-1, y)

          if y > 1:
          ret += paths(x, y-1)

          return ret


          It's a bit strange to critique this since "no closed-form solution" basically means no good solution. There are ways of speeding this up, though, that avoid that. A trivial one is memoization:



          _paths_cache = {(1, 1): 1}
          def paths(x, y):
          if (x, y) in _paths_cache:
          return _paths_cache[x, y]

          ret = 0

          if x > 1:
          ret += paths(x-1, y)

          if y > 1:
          ret += paths(x, y-1)

          _paths_cache[x, y] = ret
          return ret





          share|improve this answer





















          • What is closed-form solution?
            – overexchange
            Jun 30 '15 at 12:34










          • So, ret=0, executes only once?
            – overexchange
            Jun 30 '15 at 12:35










          • ${(x-1) + (y-1)} choose {y-1}$
            – Veedrac
            Jun 30 '15 at 13:35












          • ret = 0 executes nearly once per call to paths, which is approximately $xy$ times.
            – Veedrac
            Jun 30 '15 at 13:40






          • 1




            Each call to the function has a different ret. Look at each function call in isolation: find_number_of_paths(4, 3) is equal to find_number_of_paths(3, 3) + find_number_of_paths(4, 2), so we add each to ret and return the answer.
            – Veedrac
            Jul 1 '15 at 0:28











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f95209%2finsect-combinatorics-challenge%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          5














          Using nonlocal rather than global is certainly good, but better yet would be returning values.



          def paths(m, n):
          def find_number_of_paths(x, y):
          if x == 0 and y == 0:
          return 1

          ret = 0

          if x > 0:
          ret += find_number_of_paths(x-1, y)

          if y > 0:
          ret += find_number_of_paths(x, y-1)

          return ret

          return find_number_of_paths(m-1, n-1)


          That lets us elide the outer function entirely:



          def paths(x, y):
          if x == 1 and y == 1:
          return 1

          ret = 0

          if x > 1:
          ret += paths(x-1, y)

          if y > 1:
          ret += paths(x, y-1)

          return ret


          It's a bit strange to critique this since "no closed-form solution" basically means no good solution. There are ways of speeding this up, though, that avoid that. A trivial one is memoization:



          _paths_cache = {(1, 1): 1}
          def paths(x, y):
          if (x, y) in _paths_cache:
          return _paths_cache[x, y]

          ret = 0

          if x > 1:
          ret += paths(x-1, y)

          if y > 1:
          ret += paths(x, y-1)

          _paths_cache[x, y] = ret
          return ret





          share|improve this answer





















          • What is closed-form solution?
            – overexchange
            Jun 30 '15 at 12:34










          • So, ret=0, executes only once?
            – overexchange
            Jun 30 '15 at 12:35










          • ${(x-1) + (y-1)} choose {y-1}$
            – Veedrac
            Jun 30 '15 at 13:35












          • ret = 0 executes nearly once per call to paths, which is approximately $xy$ times.
            – Veedrac
            Jun 30 '15 at 13:40






          • 1




            Each call to the function has a different ret. Look at each function call in isolation: find_number_of_paths(4, 3) is equal to find_number_of_paths(3, 3) + find_number_of_paths(4, 2), so we add each to ret and return the answer.
            – Veedrac
            Jul 1 '15 at 0:28
















          5














          Using nonlocal rather than global is certainly good, but better yet would be returning values.



          def paths(m, n):
          def find_number_of_paths(x, y):
          if x == 0 and y == 0:
          return 1

          ret = 0

          if x > 0:
          ret += find_number_of_paths(x-1, y)

          if y > 0:
          ret += find_number_of_paths(x, y-1)

          return ret

          return find_number_of_paths(m-1, n-1)


          That lets us elide the outer function entirely:



          def paths(x, y):
          if x == 1 and y == 1:
          return 1

          ret = 0

          if x > 1:
          ret += paths(x-1, y)

          if y > 1:
          ret += paths(x, y-1)

          return ret


          It's a bit strange to critique this since "no closed-form solution" basically means no good solution. There are ways of speeding this up, though, that avoid that. A trivial one is memoization:



          _paths_cache = {(1, 1): 1}
          def paths(x, y):
          if (x, y) in _paths_cache:
          return _paths_cache[x, y]

          ret = 0

          if x > 1:
          ret += paths(x-1, y)

          if y > 1:
          ret += paths(x, y-1)

          _paths_cache[x, y] = ret
          return ret





          share|improve this answer





















          • What is closed-form solution?
            – overexchange
            Jun 30 '15 at 12:34










          • So, ret=0, executes only once?
            – overexchange
            Jun 30 '15 at 12:35










          • ${(x-1) + (y-1)} choose {y-1}$
            – Veedrac
            Jun 30 '15 at 13:35












          • ret = 0 executes nearly once per call to paths, which is approximately $xy$ times.
            – Veedrac
            Jun 30 '15 at 13:40






          • 1




            Each call to the function has a different ret. Look at each function call in isolation: find_number_of_paths(4, 3) is equal to find_number_of_paths(3, 3) + find_number_of_paths(4, 2), so we add each to ret and return the answer.
            – Veedrac
            Jul 1 '15 at 0:28














          5












          5








          5






          Using nonlocal rather than global is certainly good, but better yet would be returning values.



          def paths(m, n):
          def find_number_of_paths(x, y):
          if x == 0 and y == 0:
          return 1

          ret = 0

          if x > 0:
          ret += find_number_of_paths(x-1, y)

          if y > 0:
          ret += find_number_of_paths(x, y-1)

          return ret

          return find_number_of_paths(m-1, n-1)


          That lets us elide the outer function entirely:



          def paths(x, y):
          if x == 1 and y == 1:
          return 1

          ret = 0

          if x > 1:
          ret += paths(x-1, y)

          if y > 1:
          ret += paths(x, y-1)

          return ret


          It's a bit strange to critique this since "no closed-form solution" basically means no good solution. There are ways of speeding this up, though, that avoid that. A trivial one is memoization:



          _paths_cache = {(1, 1): 1}
          def paths(x, y):
          if (x, y) in _paths_cache:
          return _paths_cache[x, y]

          ret = 0

          if x > 1:
          ret += paths(x-1, y)

          if y > 1:
          ret += paths(x, y-1)

          _paths_cache[x, y] = ret
          return ret





          share|improve this answer












          Using nonlocal rather than global is certainly good, but better yet would be returning values.



          def paths(m, n):
          def find_number_of_paths(x, y):
          if x == 0 and y == 0:
          return 1

          ret = 0

          if x > 0:
          ret += find_number_of_paths(x-1, y)

          if y > 0:
          ret += find_number_of_paths(x, y-1)

          return ret

          return find_number_of_paths(m-1, n-1)


          That lets us elide the outer function entirely:



          def paths(x, y):
          if x == 1 and y == 1:
          return 1

          ret = 0

          if x > 1:
          ret += paths(x-1, y)

          if y > 1:
          ret += paths(x, y-1)

          return ret


          It's a bit strange to critique this since "no closed-form solution" basically means no good solution. There are ways of speeding this up, though, that avoid that. A trivial one is memoization:



          _paths_cache = {(1, 1): 1}
          def paths(x, y):
          if (x, y) in _paths_cache:
          return _paths_cache[x, y]

          ret = 0

          if x > 1:
          ret += paths(x-1, y)

          if y > 1:
          ret += paths(x, y-1)

          _paths_cache[x, y] = ret
          return ret






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jun 30 '15 at 9:56









          VeedracVeedrac

          9,1131634




          9,1131634












          • What is closed-form solution?
            – overexchange
            Jun 30 '15 at 12:34










          • So, ret=0, executes only once?
            – overexchange
            Jun 30 '15 at 12:35










          • ${(x-1) + (y-1)} choose {y-1}$
            – Veedrac
            Jun 30 '15 at 13:35












          • ret = 0 executes nearly once per call to paths, which is approximately $xy$ times.
            – Veedrac
            Jun 30 '15 at 13:40






          • 1




            Each call to the function has a different ret. Look at each function call in isolation: find_number_of_paths(4, 3) is equal to find_number_of_paths(3, 3) + find_number_of_paths(4, 2), so we add each to ret and return the answer.
            – Veedrac
            Jul 1 '15 at 0:28


















          • What is closed-form solution?
            – overexchange
            Jun 30 '15 at 12:34










          • So, ret=0, executes only once?
            – overexchange
            Jun 30 '15 at 12:35










          • ${(x-1) + (y-1)} choose {y-1}$
            – Veedrac
            Jun 30 '15 at 13:35












          • ret = 0 executes nearly once per call to paths, which is approximately $xy$ times.
            – Veedrac
            Jun 30 '15 at 13:40






          • 1




            Each call to the function has a different ret. Look at each function call in isolation: find_number_of_paths(4, 3) is equal to find_number_of_paths(3, 3) + find_number_of_paths(4, 2), so we add each to ret and return the answer.
            – Veedrac
            Jul 1 '15 at 0:28
















          What is closed-form solution?
          – overexchange
          Jun 30 '15 at 12:34




          What is closed-form solution?
          – overexchange
          Jun 30 '15 at 12:34












          So, ret=0, executes only once?
          – overexchange
          Jun 30 '15 at 12:35




          So, ret=0, executes only once?
          – overexchange
          Jun 30 '15 at 12:35












          ${(x-1) + (y-1)} choose {y-1}$
          – Veedrac
          Jun 30 '15 at 13:35






          ${(x-1) + (y-1)} choose {y-1}$
          – Veedrac
          Jun 30 '15 at 13:35














          ret = 0 executes nearly once per call to paths, which is approximately $xy$ times.
          – Veedrac
          Jun 30 '15 at 13:40




          ret = 0 executes nearly once per call to paths, which is approximately $xy$ times.
          – Veedrac
          Jun 30 '15 at 13:40




          1




          1




          Each call to the function has a different ret. Look at each function call in isolation: find_number_of_paths(4, 3) is equal to find_number_of_paths(3, 3) + find_number_of_paths(4, 2), so we add each to ret and return the answer.
          – Veedrac
          Jul 1 '15 at 0:28




          Each call to the function has a different ret. Look at each function call in isolation: find_number_of_paths(4, 3) is equal to find_number_of_paths(3, 3) + find_number_of_paths(4, 2), so we add each to ret and return the answer.
          – Veedrac
          Jul 1 '15 at 0:28


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f95209%2finsect-combinatorics-challenge%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Список кардиналов, возведённых папой римским Каликстом III

          Deduzione

          Mysql.sock missing - “Can't connect to local MySQL server through socket”