问题描述
如何在 Rust 中找到排列或组合的数量?
我在标准库中找不到这个函数,也找不到阶乘运算符(这就足够了)。
解决方法
根据@vallentin 的回答,可以进行许多优化。让我们使用相同的阶乘函数(暂时):
fn factorial(n: u64) -> u64 {
(1..=n).product()
}
对于 count_permutations
,n! / (n - r)!
实际上只是 n - r + 1
和 n
(含)之间所有数字的乘积,因此我们甚至不需要计算 2 个阶乘(这可能会溢出并涉及计算重叠数字的乘积):
fn count_permutations(n: u64,r: u64) -> u64 {
(n - r + 1..=n).product()
}
我们可以对 count_combinations
进行类似的优化:
fn count_combinations(n: u64,r: u64) -> u64 {
(n - r + 1..=n).product::<u64>() / factorial(r)
}
count_permutations
几乎完全优化,既快速又正确(如果 count_permutations
的结果可以放入 u64
中,那么它应该永远不会溢出)。
count_combinations
仍然有一些缺陷,即由于它是计算乘积然后除法,其结果可能适合u64
,但该函数仍然会溢出。您可以通过交替的乘法和除法使其非常接近非溢出:
fn count_combinations(n: u64,r: u64) -> u64 {
if r > n {
0
} else {
(1..=r).fold(1,|acc,val| acc * (n - val + 1) / val)
}
}
综合起来:
fn count_combinations(n: u64,val| acc * (n - val + 1) / val)
}
}
fn count_permutations(n: u64,r: u64) -> u64 {
(n - r + 1..=n).product()
}
fn main() {
println!("{}",count_combinations(10,6));
println!("{}",count_permutations(10,6));
}
请注意,您可以进行一些微优化,即对 r.min(n - r)
使用 r
而不是 count_combinations
,因为 count_combinations(n,r) == count_combinations(n,n - r)
,并使用较小的两者中的一个将缩小循环大小:
fn count_combinations(n: u64,r: u64) -> u64 {
if r > n {
0
} else {
(1..=r.min(n - r)).fold(1,val| acc * (n - val + 1) / val)
}
}
,
标准库不包含任何用于计算数字阶乘的运算符或函数。
相反,您可以使用 factorial
crate 或您可以使用 num
crate,其中 Rust Cookbook 包括一个示例。这是 Rust Cookbook 示例的变体,不使用 num
板条箱。
fn factorial(n: u64) -> u64 {
let mut f = 1;
for i in 1..=n {
f *= i;
}
f
}
与 commented by L. F. 一样,这可以使用 product()
表达得更短,product()
的文档中包含一个示例。
fn factorial(n: u64) -> u64 {
(1..=n).product()
}
标准库也没有用于计算给定 n
和 r
会给出的排列或组合数量的函数。相反,您可以将公式转换为函数,如下所示:
/// n! / (r! * (n - r)!)
fn count_combinations(n: u64,r: u64) -> u64 {
factorial(n) / (factorial(r) * factorial(n - r))
}
/// n! / (n - r)!
fn count_permutations(n: u64,r: u64) -> u64 {
factorial(n) / factorial(n - r)
}
fn main() {
println!("{}",6)); // Prints `210`
println!("{}",6)); // Prints `151200`
}
如果您确实想要产生排列和/或组合,那么您可以使用 itertools
crate 并专门使用 permutations()
和 combinations()
函数。