我是Rust的新手,但作为Haskell的粉丝,我非常感谢match
在Rust中的工作方式。现在我面临着一个罕见的情况,我确实需要堕落 - 从某种意义上说,我希望能够执行几个重叠的所有匹配情况。这有效:
fn options(stairs: i32) -> i32 {
if stairs == 0 {
return 1;
}
let mut count: i32 = 0;
if stairs >= 1 {
count += options(stairs - 1);
}
if stairs >= 2 {
count += options(stairs - 2);
}
if stairs >= 3 {
count += options(stairs - 3);
}
count
}
我的问题是,这是否是Rust中的惯用语或是否有更好的方法。
编辑:上下文是来自破解编码面试的问题:“孩子正在使用 n 步骤跑上楼梯,可以跳1步,2步,或一次3个步骤。实施一种方法来计算孩子爬楼梯的可能方式。“
答案 0 :(得分:7)
基于definition of the tribonacci sequence,我发现你可以用这样更简洁的方式写出来:
fn options(stairs: i32) -> i32 {
match stairs {
0 => 0,
1 => 1,
2 => 1,
3 => 2,
_ => options(stairs - 1) + options(stairs - 2) + options(stairs - 3)
}
}
我还建议将功能定义更改为仅接受正整数,例如u32
。
答案 1 :(得分:7)
为了回答这个一般性的问题,我认为<div class="a">
<p>This is some text.</p>
</div>
<div class="b">
<p>This is some text.</p>
</div>
和堕落在某种程度上是对立的。
match
用于根据不同的模式执行不同的操作。大多数情况下,通过模式匹配提取的值非常不同,因此没有任何意义。
相反,引用指向序列的操作。表达序列的方法有很多种:递归,迭代,......
在您的情况下,例如,可以使用循环:
match
当然,在这个特定的例子中,我发现@ljedrz'解决方案更加优雅。
答案 2 :(得分:2)
我会建议Rust中的avoid recursion。最好使用iterators:
struct Trib(usize, usize, usize);
impl Default for Trib {
fn default() -> Trib {
Trib(1, 0, 0)
}
}
impl Iterator for Trib {
type Item = usize;
fn next(&mut self) -> Option<usize> {
let &mut Trib(a, b, c) = self;
let d = a + b + c;
*self = Trib(b, c, d);
Some(d)
}
}
fn options(stairs: usize) -> usize {
Trib::default().take(stairs + 1).last().unwrap()
}
fn main() {
for (i, v) in Trib::default().enumerate().take(10) {
println!("i={}, t={}", i, v);
}
println!("{}", options(0));
println!("{}", options(1));
println!("{}", options(3));
println!("{}", options(7));
}
答案 3 :(得分:1)
你的代码对我来说看起来很地道,尽管@ljedrz 建议对相同的策略进行更优雅的重写。
由于这是一个面试问题,值得一提的是,这两种解决方案都不会被视为一个惊人的答案,因为这两种解决方案都占用楼梯数量的指数时间。
如果我想参加编码面试,我可能会写以下内容:
fn options(stairs: usize) -> u128 {
let mut o = vec![1, 1, 2, 4];
for _ in 3..stairs {
o.push(o[o.len() - 1] + o[o.len() - 2] + o[o.len() - 3]);
}
o[stairs]
}
我们不是每次都重新计算 options(n)
,而是将每个值缓存在一个数组中。因此,这应该以线性时间而不是指数时间运行。我还切换到 u128
以便能够返回更大输入的解决方案。
请记住,这不是最有效的解决方案,因为它使用线性空间。您可以通过只跟踪数组的最后三个元素来避免使用常量空间。我选择它是为了在简洁性、可读性和效率之间做出折衷。