法一(动态规划)
/**
* 法一(动态规划)
* 时间复杂度:O(m * n)
* 空间复杂度:O(m * n)
* (1)确定dp数组以及下标的含义
* dp[i][j]表示从(0,0)出发,到(i,j)有dp[i][j]条不同的路径
* (2)确定递推公式
* dp[i][j] = dp[i - 1][j] + dp[i][j - 1] // dp[i][j]只有从上方和左方这两个方向过来
* (3)确定dp数组如何初始化
* dp[i][0]和dp[0][j]一定都是1
* (4)确定遍历顺序
* dp[i][j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了
*
* @param m
* @param n
* @return
*/
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
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];
}
法二(动态规划 + 滚动数组)
/**
* 法二(动态规划 + 滚动数组)
* 时间复杂度:O(m * n)
* 空间复杂度:O(n)
* 滚动数组
* (1)滚动数组是一种能够在动态规划中降低空间复杂度的方法
* (2)有时某些二维dp方程可以直接降阶到一维,在某些题目中甚至可以降低时间复杂度
* (3)通过观察dp方程来判断需要使用哪些数据,可以抛弃哪些数据,一旦找到关系,就可以用新的数据不断覆盖旧的数据来减少空间的使用
*
* @param m
* @param n
* @return
*/
public int uniquePaths_2(int m, int n) {
int[] dp = new int[n];
for (int i = 0; i < n; i++) {
dp[i] = 1;
}
for (int i = 1; i < m; i++) { // 从上到下
for (int j = 1; j < n; j++) { // 从左到右
dp[j] += dp[j - 1];
}
}
return dp[n - 1];
}
法三(组合)
/**
* 法三(组合)
* 时间复杂度:O(min(m,n))
* 空间复杂度:O(1)
* 排列组合概念
* (1)排列
* 从n个不同元素中取出m(m<=n)个元素的排列数,用符号A(n,m)表示,规定0! = 1
* A(n,m) = n*(n-1)*...*(n-m+1) = n!/(n-m)!
* (2)组合
* 从n个不同元素中取出m(m<=n)个元素的组合数,用符号C(n,m)表示,规定0! = 1
* C(n,m) = A(n,m)/m! = C(n,n-m)
* 思路:
* (1)一共m,n的话,无论怎么走,走到终点都需要m+n-2步
* (2)在这m+n-2步中,一定有m-1步是要向下走的,不用管什么时候向下走
* (3)可以转化为,给你m+n-2个不同的数,随便取m-1个数,有几种取法,直接计算C(m+n-2,m-1)即可
* (4)C(m+n-2,m-1) = C(m+n-2,n-1) = C(m+n-2,min(m-1,n-1)) = (m+n-2)! / ((n-1)!(m-1)!)
*
* @param m
* @param n
* @return
*/
public int uniquePaths_3(int m, int n) {
int up = m + n - 2; // 分子
int down = Math.min(m - 1, n - 1); // 分母min(m - 1, n - 1)!是保留下来的,其余的跟分子抵消了
double ans = 1.0; // 防止溢出
while (down > 0) { // 保留下来的分子和分母阶乘的次数相等
ans *= up * 1.0 / down;
up--;
down--;
}
return (int) (ans + 0.5); // 四舍五入
}
本地测试
/**
* 62. 不同路径
*/
lay.showTitle(62);
Solution62 sol62 = new Solution62();
System.out.println(sol62.uniquePaths(3, 7));
System.out.println(sol62.uniquePaths_2(3, 7));
System.out.println(sol62.uniquePaths_3(3, 7));