Problem overview
The function factorial receives a non-negative integer n and returns n!, the product 1 * 2 * 3 * ... * n. For n = 5 the answer is 1 * 2 * 3 * 4 * 5 = 120. By convention, 0! is 1: the product of no numbers is 1.
The statement asks for O(n) time and O(1) extra space.
Approach: build the product one factor at a time
Keep a variable fact that holds the product so far. Start it at 1, because multiplying by 1 changes nothing, so it is the right starting point for a product, just as 0 is for a sum. Then walk i from 1 to n and multiply fact by i each time.
For n = 4, fact goes 1, then 1, 2, 6, 24: after the pass for i = 1 it is 1!, after i = 2 it is 2!, after i = 3 it is 3!, and after i = 4 it is 4!. Each pass extends the previous factorial by one factor.
Step by step
- Declare
factwith:=and the value 1. - Loop with
ifrom 1 throughn, so that each factor ofn!is used exactly once. The condition isi <= n. - Multiply inside the loop:
fact *= i. - Return
factafter the loop.
The solution in Go
func factorial(n int) int {
fact := 1
for i := 1; i <= n; i++ {
fact *= i
}
return fact
}
Go details:
*=is short forfact = fact * i.- Fixed-size integers. Go's
intis 64 bits here. Factorials grow fast, and the largest one that fits is 20!, which is 2432902008176640000. Past that, Go does not report an error: the multiplication wraps around silently. Running this function,factorial(21)gives-4249290049419214848, a negative number. Tests with larger inputs would need themath/bigpackage. - The empty loop. For
n = 0, the condition1 <= 0is false, the body never runs, and the function returns the initial 1, which is the correct value of 0!. - No recursion needed. A recursive version is possible, but a loop uses constant stack space, which fits the stated
O(1)space.
Why the starting value is 1
An accumulator must start at a value that doesn't disturb the first operation. For a sum, that is 0, since 0 + x is x. For a product, it is 1, since 1 * x is x. Starting fact at 0 would turn every product into 0, and the loop would look correct while always answering 0. The same reasoning explains 0! = 1: with no factors to multiply, the result is the starting value.
Tracing n = 5
Start with fact equal to 1. The pass for i = 1 keeps it at 1, i = 2 makes it 2, i = 3 makes it 6, i = 4 makes it 24, and i = 5 makes it 120. The loop ends because 6 is not less than or equal to 5, and the function returns 120.
Complexity
Time: O(n). The loop runs exactly n times, with one multiplication each.
Space: O(1). Only fact and i are stored.
Edge cases and common mistakes
- n = 0. The answer is 1, not 0. Starting
factat 0 would make every result 0. - n = 1. One pass multiplies 1 by 1, so the result is 1.
- Starting the loop at 0. The first multiplication would turn
factinto 0, and it would stay 0. - Using
i < n. The last factor would be missing:n = 5would give 24. - Overflow past 20.
factorial(20)is correct, whilefactorial(21)wraps to a wrong, negative value. - Declaring
factinside the loop. It would be reset on every pass and out of scope for thereturn.
Testing
factorial(5)gives120.factorial(0)gives1.factorial(1)gives1.factorial(20)gives2432902008176640000.