# [62. Unique Paths](https://leetcode.com/problems/unique-paths/)
# 思路

## 思路一
### 常规版
题目要求从网格矩形的左上角移动到右下角共有多少可能的路径，一次移动只能向右或向下。      
就是一个简单的递归，设置一个大小为`mxn`的数组dp（初始值全为1）, dp[i][j]代表从左上角到达位置第i行第j列的路径数，
则根据题意可知`dp[i][j] = dp[i - 1][j] + dp[i][j - 1]`。最终的返回结果就是dp[m-1][n-1]。       
时间复杂度O(mn)，空间复杂度O(mn)

### 空间改进版1
思路一的空间还有改进空间，因为每次计算dp[i][j]时只用到了`dp[i - 1][j]`和`dp[i][j - 1]`，即每次更新只用到了dp的两行。所以我们没必要开那么大一个二维数组而只用开辟两个大小为m的一维数组cur和pre就行了，分别代表当前行和前一行。然后将思路一中的`dp[i][j] = dp[i-1][j] + dp[i][j-1]` 改成`cur[i] = cur[i - 1] + pre[i]`即可（每轮循环后要对调指针pre和cur以更新pre，具体见代码）。      
时间复杂度O(mn)，空间复杂度O(m)

### 空间改进版2
仔细分析空间改进版1可知，数组pre也是多余的，只需将`cur[i] = cur[i - 1] + pre[i]`改成`cur[i] += cur[i - 1]`即可。此时将进一步节约空间。       
时间复杂度O(mn)，空间复杂度O(m)

## 思路二
这题就是之前高中做过的一个数学题。考虑mxn的网格，机器人要想到达目的地必须一共向下走m-1步、向右走n-1步，顺序不限。     
所以这题转换成一个排列组合题: 有两种球分别m-1、n-1个，将这些球排成一排，一共有多少种排法？很明显答案是(m+n-2)!/[(m-1)!(n-1)!]种（即先进行全排列再消序）。     
时间复杂度O(min(m, n)), 空间复杂度O(1) 
    

# C++

## 思路一
### 常规版
``` C++
class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>>dp(m, vector<int>(n, 1));
        for(int i = 1; i < m; i++)
        for(int j = 1; j < n; j++)
            dp[i][j] = dp[i-1][j] + dp[i][j-1];
        
        return dp[m-1][n-1];
    }
};
```
### 空间改进版1
``` C++
class Solution {
public:
    int uniquePaths(int m, int n) {
        if (m > n) return uniquePaths(n, m); 
        vector<int> pre(m, 1);
        vector<int> cur(m, 1);
        for (int j = 1; j < n; j++) {
            for (int i = 1; i < m; i++)
                cur[i] = cur[i - 1] + pre[i];
            swap(pre, cur);
            // pre已被更新, 此时cur中的数据为无用的
        }
        return pre[m - 1];
    }
};
```
### 空间改进版2
``` C++
class Solution {
public:
    int uniquePaths(int m, int n) {
        if (m > n) return uniquePaths(n, m); 
        vector<int> cur(m, 1);
        for (int j = 1; j < n; j++) {
            for (int i = 1; i < m; i++)
                cur[i] += cur[i - 1];
        }
        return cur[m - 1];
    }
};
```

## 思路二
``` C++
class Solution {
public:
    int uniquePaths(int m, int n) {
        if(m == 1 || n == 1) return 1;
        long long res = 1, tmp = 1;
        if(m < n){ // 保证m > n, 否则可能会溢出
           int mbk = m;
            m = n;
            n = mbk;
        }
        for(int i = m; i <= m + n - 2; i++) res *= i; // 计算 (m + n - 2)! / (m - 1)!
        for(int i = 2; i <= n - 1; i++) tmp *= i; // 计算 (n-1)!
        res /= tmp;
        return (int)res;
    }
};
```
