Tail Recursion Optimization in TypeScript
Tail recursion is a specific form of recursion where the recursive call is the very last operation performed in the function. Many functional programming languages optimize tail recursion into iterative loops, preventing stack overflow errors that can occur with deep recursion. This challenge asks you to implement a function that utilizes tail recursion and then demonstrates how to optimize it using a helper function to achieve the same result iteratively.
Problem Description
You are tasked with implementing a function factorialTailRecursive(n: number) that calculates the factorial of a non-negative integer n using tail recursion. Then, you must create a second function factorialIterative(n: number) that achieves the same result without recursion, effectively demonstrating the optimization of tail recursion. The iterative version should mimic the logic of the tail-recursive version.
What needs to be achieved:
- Implement
factorialTailRecursive(n)using tail recursion. This function should take a numbernas input and return its factorial. - Implement
factorialIterative(n)using an iterative approach (e.g., afororwhileloop). This function should also take a numbernas input and return its factorial. - Ensure both functions produce the same output for the same input.
Key Requirements:
factorialTailRecursive(n)must be tail-recursive. This means the recursive call must be the very last operation in the function.factorialIterative(n)must be iterative and avoid recursion entirely.- Both functions must handle the base case of
n = 0correctly (factorial of 0 is 1). - Both functions must handle invalid input (negative numbers) gracefully. Return
NaNifnis negative.
Expected Behavior:
- For
n = 0, both functions should return1. - For
n = 5, both functions should return120. - For
n = -1, both functions should returnNaN.
Edge Cases to Consider:
n = 0(base case)n < 0(invalid input)- Large values of
n(potential for integer overflow, though this is not a primary focus of the challenge).
Examples
Example 1:
Input: 5
Output: 120
Explanation: 5! = 5 * 4 * 3 * 2 * 1 = 120
Example 2:
Input: 0
Output: 1
Explanation: 0! = 1 (by definition)
Example 3:
Input: -1
Output: NaN
Explanation: Factorial is not defined for negative numbers.
Constraints
nwill be an integer.ncan be positive, negative, or zero.- The functions should be reasonably efficient. While performance optimization beyond tail recursion/iteration is not the primary focus, avoid unnecessary computations.
- The iterative function should mimic the logic of the tail-recursive function.
Notes
- Tail recursion optimization is not guaranteed in all JavaScript/TypeScript environments. The goal here is to demonstrate the concept of tail recursion and how it can be transformed into an iterative solution.
- Think about how you can use an accumulator variable in the tail-recursive function to build up the factorial value.
- The iterative function should use a loop to achieve the same result as the tail-recursive function with the accumulator.
- Consider using
Number.NaNto represent "Not a Number" for invalid input.