62. 不同路径 - 力扣(LeetCode)
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
示例 1:
输入:m = 3, n = 7 输出:28
示例 2:
输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右
3. 向下 -> 向右 -> 向下
示例 3:
输入:m = 7, n = 3 输出:28
提示:
1 <= m, n <= 100
2 * 109
class Solution {
// m 行
// n 列
// 下:m-1
// 右:n-1
public int uniquePaths(int m, int n) {
// 下面这两个数举一个具体例子就能想出来是怎么算的
// 向右一共需要走多少步
int right = n - 1;
// 从左上角到右下角一共需要走多少步
int all = m + n - 2;
// 求排列组合公式中的分子,为了避免溢出,这里用long
long o1 = 1;
// 求排列组合公式中的分母
long o2 = 1;
// 我们通过举一个具体的例子化简就可以知道,公式中分子是从right+1开始累乘的
// 分母是从1开始累乘的,并且o1乘进去的个数 一定等于o2乘进去的个数
// 计算C(right, all)
for (int i = 1, j = right + 1; j <= all; i++, j++) {
// 计算分子
o1 *= j;
// 计算坟墓
o2 *= i;
// 在计算阶乘的过程中要一直进行约分化简,因为分子是有可能溢出的
// 得到o1和o2的最大公约数
long gcd = gcd(o1, o2);
// o1和o2同时除以他们的最大公约数,就相当于分子和分母进行约分
o1 /= gcd;
o2 /= gcd;
}
// 最后分母o2一定会被约分成1,所以最终返回分子o1就是排列组合公式的答案。注意要转换为int
// 这里其实返回(int)(o1 / o2)也是对的
return (int)o1;
}
// 辗转相除法求a和b的最大公约数
public long gcd(long a, long b) {
if (b == 0) {
return a;
} else {
return gcd(b, a % b);
}
}
}
从左上角到右下加,假设整体最多往右5步,往下4步,一共9步。
其实就相当于求94。这样就会把所有横着走和竖着走的排列组合全都求出来了。
小心溢出,有可能不溢出,但是X!可能溢出。所以在用公式求时,要注意阶乘不溢出。