Skip to main content

Factorial of a Given Number

Difficulty: Easy​

Problem Statement​

You are given an integer n. Return the value of n! or n factorial.

Factorial of a number is the product of all positive integers less than or equal to that number.

Mathematical Definition​

For any non-negative integer n:

  • n! = n × (n-1) × (n-2) × ... × 2 × 1
  • 0! = 1 (by definition)
  • 1! = 1

Examples​

Example 1:
Input: n = 2
Output: 2
Explanation: 2! = 1 × 2 = 2.

Example 2:
Input: n = 0
Output: 1
Explanation: 0! is defined as 1.

Example 3:
Input: n = 5
Output: 120
Explanation: 5! = 1 × 2 × 3 × 4 × 5 = 120.

Example 4:
Input: n = 1
Output: 1
Explanation: 1! = 1.

Example 5:
Input: n = 4
Output: 24
Explanation: 4! = 1 × 2 × 3 × 4 = 24.

Constraints​

  • 0 ≤ n ≤ 12 (due to integer overflow limitations)
  • n is a non-negative integer

Key Concepts​

  • Factorial: Product of all positive integers from 1 to n
  • Base Case: 0! = 1 and 1! = 1
  • Multiplicative Accumulation: Build result by multiplying consecutive integers
  • Integer Overflow: Large factorials exceed standard integer limits

Algorithm / Intuition​

Approach: Iterative Multiplication​

The strategy is to:

  1. Initialize a result variable to 1 (multiplicative identity)
  2. Multiply the result by each integer from 1 to n
  3. Accumulate the product in each iteration
  4. Return the final product

Core Logic:​

  • Start with result = 1 (since multiplying by 1 doesn't change the value)
  • For each number from 1 to n, multiply it with the current result
  • This builds the factorial incrementally: 1 → 1×2 → 1×2×3 → 1×2×3×4 → ...

Mathematical Process:​

For n = 5:
Start: result = 1
Step 1: result = 1 × 1 = 1
Step 2: result = 1 × 2 = 2
Step 3: result = 2 × 3 = 6
Step 4: result = 6 × 4 = 24
Step 5: result = 24 × 5 = 120
Final: 5! = 120

Step-by-Step Algorithm:​

  1. Initialize ans = 1 to store the factorial result
  2. Use a loop from i = 1 to i = n (inclusive)
  3. In each iteration, multiply ans by i
  4. After the loop, ans contains n!
  5. Return the result

Why Start with 1?​

  • Multiplicative Identity: 1 × anything = anything
  • Handles Edge Cases: When n = 0, loop doesn't execute, returns 1 (correct for 0!)
  • Base for Accumulation: Provides starting point for multiplication chain

DryRun Example:​

Input: n = 4

Initial: n = 4, ans = 1

Iteration 1: i = 1
- ans = ans * i = 1 * 1 = 1

Iteration 2: i = 2
- ans = ans * i = 1 * 2 = 2

Iteration 3: i = 3
- ans = ans * i = 2 * 3 = 6

Iteration 4: i = 4
- ans = ans * i = 6 * 4 = 24

Loop ends as i > n
Answer: ans = 24 (4! = 24)

Code Solutions​

Java​

class Solution {
public int factorial(int n) {
// Initialize result to 1 (multiplicative identity and base case for 0!)
int ans = 1;

// Multiply all integers from 1 to n
for(int i = 1; i <= n; i++) {
// Accumulate the product: ans = ans * i
ans = ans * i;
}

// Return the final factorial result
return ans;
}
}

JavaScript​

class Solution {
factorial(n) {
// Initialize result to 1 (multiplicative identity and base case for 0!)
let ans = 1;

// Multiply all integers from 1 to n
for (let i = 1; i <= n; i++) {
// Accumulate the product: ans = ans * i
ans = ans * i;
}

// Return the final factorial result
return ans;
}
}

Python​

class Solution:
def factorial(self, n):
# Initialize result to 1 (multiplicative identity and base case for 0!)
ans = 1

# Multiply all integers from 1 to n using range(1, n+1)
for i in range(1, n + 1):
# Accumulate the product: ans = ans * i
ans = ans * i

# Return the final factorial result
return ans

Complexity Analysis​

Time Complexity: O(n)​

  • We perform exactly n iterations of the loop
  • Each iteration does constant time work (one multiplication)
  • Total time is proportional to n

Space Complexity: O(1)​

  • We use only a constant amount of extra space
  • Variables: ans, i (constant space regardless of input size)

Alternative Approaches​

1. Recursive Approach​

// Java
class Solution {
public int factorial(int n) {
// Base case: 0! = 1 and 1! = 1
if (n <= 1) return 1;

// Recursive case: n! = n × (n-1)!
return n * factorial(n - 1);
}
}

Pros: Mathematical elegance, matches definition
Cons: O(n) space due to recursion stack, potential stack overflow

2. Built-in Functions (Language Specific)​

# Python
import math

class Solution:
def factorial(self, n):
return math.factorial(n)
// Java (using streams for educational purposes)
class Solution {
public int factorial(int n) {
return java.util.stream.IntStream
.rangeClosed(1, n)
.reduce(1, (a, b) -> a * b);
}
}

3. While Loop Approach​

// Java
class Solution {
public int factorial(int n) {
int ans = 1;
int i = 1;

while (i <= n) {
ans *= i;
i++;
}

return ans;
}
}

4. Reverse Loop (n to 1)​

// Java
class Solution {
public int factorial(int n) {
int ans = 1;

// Loop from n down to 1
for (int i = n; i >= 1; i--) {
ans *= i;
}

return ans;
}
}

Factorial Values and Integer Limits​

Common Factorial Values:​

0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5,040
8! = 40,320
9! = 362,880
10! = 3,628,800
11! = 39,916,800
12! = 479,001,600
13! = 6,227,020,800 (exceeds 32-bit int)

Integer Overflow Considerations:​

  • 32-bit int: Can safely store up to 12! (479,001,600)
  • 64-bit long: Can safely store up to 20!
  • Beyond that: Need BigInteger or special handling

Edge Cases to Consider​

  1. n = 0: Should return 1 (0! = 1 by definition)
  2. n = 1: Should return 1 (1! = 1)
  3. Small values (2, 3, 4): Basic test cases
  4. Boundary value (12): Largest factorial fitting in 32-bit int
  5. Large values (>12): Would cause integer overflow

Detailed Edge Case Analysis​

// Edge cases with explanations
Input: 0 → Output: 1 (mathematical definition: 0! = 1)
Input: 1 → Output: 1 (1! = 1)
Input: 2 → Output: 2 (2! = 2×1 = 2)
Input: 5 → Output: 120 (5! = 5×4×3×2×1 = 120)
Input: 12 → Output: 479001600 (largest that fits in 32-bit int)

Test Cases​

public void testFactorial() {
Solution sol = new Solution();

// Edge cases
assert sol.factorial(0) == 1; // 0! = 1
assert sol.factorial(1) == 1; // 1! = 1

// Small values
assert sol.factorial(2) == 2; // 2! = 2
assert sol.factorial(3) == 6; // 3! = 6
assert sol.factorial(4) == 24; // 4! = 24
assert sol.factorial(5) == 120; // 5! = 120

// Larger values
assert sol.factorial(6) == 720; // 6! = 720
assert sol.factorial(10) == 3628800; // 10! = 3,628,800
assert sol.factorial(12) == 479001600; // 12! = 479,001,600
}

Step-by-Step Visualization​

Visual Example: n = 5​

Step 0: ans = 1 (initial)
Step 1: i=1, ans = 1 * 1 = 1
Step 2: i=2, ans = 1 * 2 = 2
Step 3: i=3, ans = 2 * 3 = 6
Step 4: i=4, ans = 6 * 4 = 24
Step 5: i=5, ans = 24 * 5 = 120

Result: 5! = 120

Visual Example: n = 0​

Initial: ans = 1
Loop condition: i=1, 1 <= 0? No
Loop doesn't execute
Result: 0! = 1 (correct by definition)

Common Mistakes to Avoid​

  1. Wrong Initialization: Starting with ans = 0 instead of ans = 1
  2. Off-by-One Errors: Using i < n instead of i <= n in loop condition
  3. Forgetting Edge Cases: Not handling n = 0 correctly
  4. Integer Overflow: Not considering that large factorials exceed int limits
  5. Loop Range: Using wrong range in Python (range(1, n) instead of range(1, n+1))

Optimization Techniques​

1. Early Termination for Zero​

class Solution {
public int factorial(int n) {
if (n == 0 || n == 1) return 1; // Handle base cases immediately

int ans = 1;
for (int i = 2; i <= n; i++) { // Start from 2 since ans*1 = ans
ans *= i;
}
return ans;
}
}

2. Using Compound Assignment​

class Solution {
public int factorial(int n) {
int ans = 1;
for (int i = 1; i <= n; i++) {
ans *= i; // Equivalent to ans = ans * i
}
return ans;
}
}

Mathematical Properties​

1. Factorial Growth Rate​

  • Factorials grow extremely rapidly (faster than exponential)
  • Each step multiplies by an increasing number
  • This is why integer overflow happens quickly

2. Factorial Formula​

  • Recursive definition: n! = n × (n-1)!
  • Product notation: n! = ∏(i=1 to n) i
  • Stirling's approximation: n! ≈ √(2πn) × (n/e)^n

3. Applications​

  • Permutations: Number of ways to arrange n objects = n!
  • Combinations: Used in binomial coefficients C(n,r) = n!/(r!(n-r)!)
  • Probability: Calculating probabilities in various scenarios

Extensions and Variations​

1. Handle Large Numbers (Using BigInteger)​

// Java
import java.math.BigInteger;

class Solution {
public BigInteger factorial(int n) {
BigInteger ans = BigInteger.ONE;
for (int i = 1; i <= n; i++) {
ans = ans.multiply(BigInteger.valueOf(i));
}
return ans;
}
}

2. Double Factorial (n!!)​

// Double factorial: n!! = n × (n-2) × (n-4) × ...
class Solution {
public int doubleFactorial(int n) {
int ans = 1;
for (int i = n; i > 0; i -= 2) {
ans *= i;
}
return ans;
}
}

3. Factorial with Memoization​

// Cache results to avoid recomputation
class Solution {
private Map<Integer, Integer> memo = new HashMap<>();

public int factorial(int n) {
if (n <= 1) return 1;
if (memo.containsKey(n)) return memo.get(n);

int result = n * factorial(n - 1);
memo.put(n, result);
return result;
}
}

Performance Comparison​

ApproachTime ComplexitySpace ComplexityProsCons
IterativeO(n)O(1)Optimal space, simpleNone significant
RecursiveO(n)O(n)Elegant, matches definitionStack overflow risk
Built-inO(n)O(1)Very conciseLess educational
MemoizedO(n)O(n)Fast for repeated callsExtra memory usage

Key Learning Points​

  1. Multiplicative Accumulation: Building products through iterative multiplication
  2. Loop Design: Proper range and boundary conditions
  3. Base Cases: Handling edge cases like 0! = 1
  4. Integer Overflow: Understanding limits of data types
  5. Mathematical Definitions: Converting mathematical concepts to code

  1. Permutations: Calculate nPr = n!/(n-r)!
  2. Combinations: Calculate nCr = n!/(r!(n-r)!)
  3. Fibonacci Sequence: Another classic recursive/iterative problem
  4. Power Calculation: Computing x^n efficiently
  5. GCD/LCM: Other mathematical computations
  6. Prime Factorization: Breaking numbers into prime factors

Follow-up Questions​

  1. How would you handle very large factorials that don't fit in standard integers?
  2. Can you optimize this for multiple factorial calculations?
  3. How would you implement factorial modulo a prime number?
  4. What's the most efficient way to calculate n!/k! for given n and k?
  5. How would you implement this using only recursion?

Summary​

The factorial problem is a fundamental mathematical computation that demonstrates:

  • Basic loop design and accumulation patterns
  • Handling mathematical edge cases
  • Understanding integer overflow limitations
  • Converting mathematical definitions to efficient code

Time Complexity: O(n) - must multiply n numbers
Space Complexity: O(1) - constant extra space
Key Insight: Use multiplicative accumulation starting from 1

This problem serves as an excellent introduction to iterative algorithms and provides a foundation for more complex mathematical computations. The iterative approach is optimal for most practical purposes, combining simplicity, efficiency, and reliability.