classSolution { private: intdfs(int i, int j, int m, int n){ if (i > m || j > n) return0; // 越界了 if (i == m && j == n) return1; // 找到一种方法,相当于找到了叶子节点 returndfs(i + 1, j, m, n) + dfs(i, j + 1, m, n); } public: intuniquePaths(int m, int n){ returndfs(1, 1, m, n); } };
动态规划
确定dp数组以及其下标的含义
1
dp[i][j],表示从(0,0)出发,到(i,j)有dp[i][j]条不同的路径
确定递推公式
1
dp[i][j] = dp[i-1][j] + dp[i][j-1]
dp数组的初始化
1 2
for (int i = 0; i < m; i ++) dp[i][0] = 1; for (int j = 0; j < n; j ++) dp[0][j] = 1;
确定遍历顺序
从左到右一层层遍历
举例推导dp数组
初始代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution { public: intuniquePaths(int m, int n){ vector<vector<int>> dp(m, vector<int>(n, 0)); for (int i = 0; i < m; i ++) dp[i][0] = 1; for (int j = 0; j < n; j ++) dp[0][j] = 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 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution { public: intuniquePaths(int m, int n){ vector<int> dp(n); for (int i = 0; i < n; i ++) dp[i] = 1; for (int j = 1; j < m; j ++) { for (int i = 1; i < n; i ++) { dp[i] += dp[i-1]; } }
return dp[n-1]; } };
数论方法
在这个图中,可以看出一共m,n的话,无论怎么走,走到终点都需要 m + n -
2 步。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution { public: intuniquePaths(int m, int n){ longlong numerator = 1; // 分子 int denominator = m - 1; // 分母 int count = m - 1; int t = m + n - 2; while (count--) { numerator *= (t--); while (denominator != 0 && numerator % denominator == 0) { numerator /= denominator; denominator--; } } return numerator; } };