Problem overview
The method Factorial(int n) takes a non-negative integer n and returns n!, the product of every whole number from 1 up to n. For n = 5 that is 1 * 2 * 3 * 4 * 5 = 120.
The statement asks for O(n) time and O(1) extra space. That means one pass over the numbers 1 to n, and a fixed number of variables no matter how large n is.
Approach: a running product
You can't compute a product in one step, but you can build it gradually. Keep a variable that holds the product so far, and multiply it by each factor in turn. For n = 4 it changes like this:
start: fact = 1
multiply 1: fact = 1
multiply 2: fact = 2
multiply 3: fact = 6
multiply 4: fact = 24
Each intermediate value is itself a factorial (1!, 2!, 3!, 4!), so when the last factor has been multiplied in, fact holds the answer. A for loop is the natural tool because the number of repetitions is known in advance: exactly n.
Step by step
- Declare
factand set it to 1. The starting value must be 1, not 0, because multiplying anything by 0 gives 0. Starting at 1 also makes the casen = 0work without special handling: the loop doesn't run, and the method returns 1, which is the correct value of 0!. - Loop with
ifrom 1 throughn. The condition isi <= n, with<=, so thatnitself is included as a factor. The loop starts at 1 rather than 0, since a factor of 0 would wipe out the product. - Multiply inside the loop.
fact *= iis shorthand forfact = fact * i. - Return
factafter the loop. The return belongs below the closing brace. Placed inside the loop, it would end the method after the first factor.
The solution in C#
class Solution {
public int Factorial(int n) {
int fact = 1;
for (int i = 1; i <= n; i++) {
fact *= i;
}
return fact;
}
}
A few C# details are worth knowing:
- The loop header has three parts.
int i = 1runs once at the start,i <= nis tested before every pass, andi++runs after every pass. The variableiexists only inside the loop, whilefact, declared before it, is still available at thereturn. intoverflow is silent. Anintis a 32-bit number whose largest value is 2,147,483,647. By default, C# arithmetic that goes past the limit wraps around without an exception and without a warning.Factorial(12)is 479001600, which fits.Factorial(13)should be 6,227,020,800, but the method returns 1932053504, a wrong number that looks perfectly normal.- Bigger results need a bigger type. Declaring
factaslongpushes the limit up to 20!, andSystem.Numerics.BigIntegerhas no practical limit. This lesson's signature usesint, so its tests stay in the range whereintis enough.
Complexity
Time: O(n). The loop runs exactly n times, and each pass does one multiplication, which takes constant time.
Space: O(1). The method only uses fact, i and the parameter n. Nothing grows with the input.
Edge cases and common mistakes
n = 0. The answer is 1. It works becausefactstarts at 1 and the loop body never runs. Startingfactat 0 would return 0 for every input.n = 1. The loop runs once and multiplies 1 by 1, so the answer is 1.- Using
i < n. The last factor is then missing, andFactorial(5)returns 24 instead of 120. - Starting the loop at 0. Then
factis multiplied by 0 on the first pass and stays 0. - Returning inside the loop. The method would stop after the first pass and return 1.
- Overflow for
nabove 12. The result wraps silently, as described above.
Testing
n = 0gives1.n = 1gives1.n = 5gives120.n = 12gives479001600.