Practice Day twenty-six:Leetcode T 62

噢吼吼,今天的Leetcode居然有图看,这么美味的图,居然是免费的吗!?
今天来品尝品尝组合数学吧,其实就是高中知识,简单的很,放高考纯送分题
核心思想:
这是一道典型的组合数学问题,即二项式定理
要从 (0, 0) 到 (m-1, n-1),总共需要走 (m-1 + n-1) 步,其中选择 (m-1) 步向下,其余为向右。
所以总路径数是:
C(m+n−2,m−1)
或者等价地:
C(m+n−2,n−1)
这就是所有理论了,有些小弟弟小妹妹还没上高中的可以先去B站学一下组合数学的知识,应该五分钟就可以学会了,这里我就不再使用过多篇幅描述了。
鉴于题目十分简单,理论十分简单,所以代码实现也十分简单,我这里就直接放出代码吧
class Solution {
public:
int uniquePaths(int m, int n) {
long long ans = 1;
for (int x = n, y = 1; y < m; ++x, ++y) {
ans = ans * x / y;
}
return ans;
}
};
使用long long定义ans是为了防止溢出
对于for循环那部分
for (int x = n, y = 1; y < m; ++x, ++y) {
ans = ans * x / y;
}
-
变量解释:
x:从n开始递增,表示组合数中的分子项。y:从1开始递增,表示分母项。- 每次循环都进行
ans = ans * x / y,即逐步计算组合数。 - 且y<m,使得最终y到达的是m-1,那么y增大了m-2个单位大小,则x到达的是n+m-2

为什么要逐步计算组合数?
在计算组合数(如 C(n, k))时,如果直接使用阶乘计算:

会出现以下几个问题:
1. 数值太大,容易溢出
- 在 C++ 中,
int的最大值是约 2.1e9,long long是约 9e18。 - 当
n很大时,比如n=50,50!是一个非常大的数(约 3e64),远远超过long long的范围。 - 直接计算阶乘会导致整数溢出,结果变成错误的负数或零。
2. 计算效率低
- 阶乘的计算需要很多次乘法操作,尤其是当
n很大时。 - 而且,即使你用
long long,也可能会因为数值太大而无法正确存储。
但是这样会出现一个问题:怎么保证这样做不会每次都能整除?要知道C++中的int不能整除可是会进行截断的!
这是因为我们算法的设计
for (int x = n, y = 1; y < m; ++x, ++y) {
ans = ans * x / y;
}
每一步的计算都是组合数,而组合数不会出现非整数。
今天的组合数学到此为止
1179

被折叠的 条评论
为什么被折叠?



