<p>There is a robot on an <code>m x n</code> grid. The robot is initially located at the <strong>top-left corner</strong> (i.e., <code>grid[0][0]</code>). The robot tries to move to the <strong>bottom-right corner</strong> (i.e., <code>grid[m - 1][n - 1]</code>). The robot can only move either down or right at any point in time.</p>

<p>Given the two integers <code>m</code> and <code>n</code>, return <em>the number of possible unique paths that the robot can take to reach the bottom-right corner</em>.</p>

<p>The test cases are generated so that the answer will be less than or equal to <code>2 * 10<sup>9</sup></code>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img src="https://assets.leetcode.com/uploads/2018/10/22/robot_maze.png" style="width: 400px; height: 183px;" />
<pre>
<strong>Input:</strong> m = 3, n = 7
<strong>Output:</strong> 28
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> m = 3, n = 2
<strong>Output:</strong> 3
<strong>Explanation:</strong> From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -&gt; Down -&gt; Down
2. Down -&gt; Down -&gt; Right
3. Down -&gt; Right -&gt; Down
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= m, n &lt;= 100</code></li>
</ul>

# # Dynamic Programming
# # Dynamic Programming, 2-Dimension DP (bruteForce), Brute Force (Time Limit Exceeded)
# class Solution:
#     def uniquePaths(self, m: int, n: int) -> int:
#         ROWS, COLS = m, n

#         def bruteForce(r, c):
#             if r >= ROWS or c >= COLS:
#                 return 0
            
#             if r == ROWS - 1 and c == COLS - 1:
#                 return 1

#             # cur = down + left
#             return bruteForce(r + 1, c) + bruteForce(r, c + 1)
        
#         return bruteForce(0, 0)

# # Time: O(2^(ROWS + COLS)), ROWS = m, COLS = n, a decision tree with 2 options and a height of m * n (the length fo path)
# # Space: O(2^(ROWS + COLS)), ROWS = m, COLS = n, call stack

# # Dynamic Programming
# # Dynamic Programming, 2-Dimension DP (memoization), Top-Down
# class Solution:
#     def uniquePaths(self, m: int, n: int) -> int:
#         ROWS, COLS = m, n
#         cache = [[0] * COLS for _ in range(ROWS)]

#         def memoization(r, c):
#             if r >= ROWS or c >= COLS:
#                 return 0
            
#             if cache[r][c] > 0:
#                 return cache[r][c]

#             if r == ROWS - 1 and c == COLS - 1:
#                 return 1
            
#             # cur = down + left
#             cache[r][c] = memoization(r + 1, c) + memoization(r, c + 1)

#             return cache[r][c]
        
#         return memoization(0, 0)

# # Time: O(ROWS * COLS), ROWS = m, COLS = n, traverse the grid, a nested for loop
# # Space: O(ROWS * COLS), ROWS = m, COLS = n, cache

# Dynamic Programming
# Dynamic Programming, 2-Dimension DP (dp), Bottom-Up
class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        ROWS, COLS = m, n
        prevRow = [0] * COLS
        prevRow[-1] = 1

        for r in reversed(range(ROWS)):
            curRow = [0] * COLS
            # curRow[COLS - 1] = 1

            for c in reversed(range(COLS)):
                if c < COLS - 1:
                    curRow[c] = curRow[c + 1] + prevRow[c]
                else:
                    curRow[c] = prevRow[c]
            
            prevRow = curRow
        
        return prevRow[0]

# Time: O(ROWS * COLS), ROWS = m, COLS = n, traverse the grid, a nested for loop
# Space: O(COLS), prevRow, curRow

# # Dynamic Programming
# # Dynamic Programming, 2-Dimension DP, Bottom-Up
# class Solution:
#     def uniquePaths(self, m: int, n: int) -> int:
#         ROWS, COLS = m, n
#         dp = [0] * COLS
#         dp[COLS - 1] = 1

#         for r in reversed(range(ROWS)): # ROWS - 1 to 0
#             for c in reversed(range(COLS)): # COLS - 1 to 0
#                 if c < COLS - 1:
#                     dp[c] = dp[c] + dp[c + 1]

#         return dp[0]

# # Time: O(ROWS * COLS), ROWS = m, COLS = n, traverse the grid, a nested for loop
# # Space: O(COLS), COLS = n, dp
16400