Problem overview
The function factorial takes a non-negative integer n and returns n!, the product of all whole numbers from 1 to n. For n = 5, 5! = 1 * 2 * 3 * 4 * 5 = 120.
The statement sets a budget of O(n) time and O(1) extra space. A single loop with one running product fits it. By convention 0! is 1, because a product with no factors is 1.
Approach
Build the product one factor at a time. A variable fact starts at 1, since multiplying by 1 changes nothing. For n = 4 its values are:
- Start:
factis 1, which is 1!. - Multiply by 2:
factis 2, which is 2!. - Multiply by 3:
factis 6, which is 3!. - Multiply by 4:
factis 24, which is 4!.
The repeated multiplication is a loop over the numbers 1 to n. Each pass multiplies the current number into fact, and after the last pass fact holds n!.
The accumulator starts at 1, not 0. A product that starts at 0 would stay 0 whatever was multiplied into it.
Step by step
- Declare
factas mutable, starting at 1. Rust variables are immutable by default, and this one changes on every pass, so it is writtenlet mut fact = 1;. - Loop over 1 to
ninclusive. The range1..=nincludesn, which is the last factor. The range1..nwould leave it out. - Multiply inside the loop.
fact *= i;folds the current factor into the running product. - Return
factonce the loop is over.
The solution in Rust
impl Solution {
fn factorial(n: i32) -> i32 {
let mut fact = 1;
for i in 1..=n {
fact *= i;
}
return fact;
}
}
Some Rust details here:
- Inclusive range.
1..=ncounts from 1 tonand includes both ends. Ifnis 0, the range is empty and the loop runs zero times, so the function returns 1, the correct value of 0!. - Type inference. The compiler gives
factthe typei32, since it is returned from a function whose return type isi32. *=is shorthand forfact = fact * i, and it needsmut.- Return.
return fact;works, and so does the bare expressionfactas the last line without a semicolon.
Complexity
Time: O(n). The loop runs exactly n times, with one multiplication per pass.
Space: O(1). Only fact and the loop variable i are stored, however large n is.
Edge cases and common mistakes
n = 0. The result is 1. The loop does not run, andfactkeeps its initial value.n = 1. The result is 1.- Starting
factat 0. Every product would be 0. - Using
1..n. The last factor is missing, sofactorial(5)would return 24 instead of 120. - Overflow. Factorials grow quickly. An
i32holds 12! = 479,001,600 but not 13! = 6,227,020,800. In an optimized build, which is how the lessons are compiled, the multiplication wraps silently:factorial(13)returns 1932053504 andfactorial(20)returns -2102132736. A debug build would panic with an overflow error instead. Inputs up to 12 are safe.
Testing
n = 5gives 120.n = 0gives 1.n = 1gives 1.n = 4gives 24.n = 12gives 479001600.
