Master the fundamentals of recursive programming through hands-on implementation and practical exercises.
Recursion is a powerful programming concept where a function solves a problem by calling itself with smaller inputs. Understanding recursion is crucial for solving complex problems and implementing elegant solutions.
Every recursive solution consists of two essential parts:
Without a proper base case, your recursion will continue indefinitely, causing a stack overflow error.
Define the stopping condition
// Example: Factorial base case
if (n == 0) return 1;
Implement the self-referential step
// Example: Factorial recursive case
return n * factorial(n - 1);
Verify the problem size decreases with each recursive call
// Example: Each call reduces n by 1
factorial(n) → factorial(n-1) → factorial(n-2) → ... → factorial(0)
public int factorial(int n) {
// Base case: factorial of 0 is 1
if (n == 0) {
return 1;
}
// Recursive case: n! = n * (n-1)!
return n * factorial(n - 1);
}
factorial(4)
└── 4 * factorial(3)
└── 4 * (3 * factorial(2))
└── 4 * (3 * (2 * factorial(1)))
└── 4 * (3 * (2 * (1 * factorial(0))))
└── 4 * (3 * (2 * (1 * 1)))
└── 4 * (3 * (2 * 1))
└── 4 * (3 * 2)
└── 4 * 6
└── 24
public int fibonacci(int n) {
// Base cases: F(0) = 0, F(1) = 1
if (n <= 0) {
return 0;
} else if (n == 1) {
return 1;
}
// Recursive case: F(n) = F(n-1) + F(n-2)
return fibonacci(n - 1) + fibonacci(n - 2);
}
fibonacci(4)
├── fibonacci(3) + fibonacci(2)
│ ├── fibonacci(2) + fibonacci(1) + fibonacci(1) + fibonacci(0)
│ │ ├── fibonacci(1) + fibonacci(0) + 1 + 0
│ │ │ ├── 1 + 0 + 1 + 0
│ │ │ └── 2
└── 3
Any recursive solution can be rewritten as an iterative solution, but recursive solutions are often more elegant and easier to understand for certain problems.
// Recursive factorial
public int factorialRecursive(int n) {
if (n == 0) return 1;
return n * factorialRecursive(n - 1);
}
// Iterative factorial
public int factorialIterative(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}
return result;
}
Improve recursive solutions by caching previously computed results to avoid redundant calculations.
public int fibonacciMemoized(int n) {
Map memo = new HashMap<>();
return fibMemo(n, memo);
}
private int fibMemo(int n, Map memo) {
// Check if already computed
if (memo.containsKey(n)) {
return memo.get(n);
}
// Base cases
if (n <= 0) return 0;
if (n == 1) return 1;
// Compute and store result
int result = fibMemo(n - 1, memo) + fibMemo(n - 2, memo);
memo.put(n, result);
return result;
}
Implement a recursive function to calculate the factorial of a number.
public int factorial(int n) {
// Your implementation here
// Remember: factorial(n) = n * factorial(n-1)
// Base case: factorial(0) = 1
}
Write a recursive function to find the nth Fibonacci number.
public int fibonacci(int n) {
// Your implementation here
// Remember: F(n) = F(n-1) + F(n-2)
// Base cases: F(0) = 0, F(1) = 1
}
Create a recursive function to reverse a string.
public String reverseString(String str) {
// Your implementation here
// Base case: Empty string or single character
// Recursive case: First character goes to the end
}
Hint: For a string "hello", think of it as the first character 'h' plus the rest "ello". The reversed string would be the reversed "ello" plus 'h'.
Implement a recursive function to calculate x raised to the power of n (x^n).
public double power(double x, int n) {
// Your implementation here
// Handle negative exponents too!
// Consider that x^n = x * x^(n-1)
}
Write a recursive function to find the sum of all elements in an array.
public int sumArray(int[] arr) {
return sumArrayHelper(arr, 0);
}
private int sumArrayHelper(int[] arr, int index) {
// Your implementation here
// Base case: index reaches the end of array
// Recursive case: current element + sum of rest
}
Implement a recursive binary search algorithm to find an element in a sorted array.
public int binarySearch(int[] arr, int target) {
return binarySearchHelper(arr, target, 0, arr.length - 1);
}
private int binarySearchHelper(int[] arr, int target, int low, int high) {
// Your implementation here
// Base case: element not found or found
// Recursive case: search in left or right half
}
Implement the classic Tower of Hanoi problem using recursion. Move n disks from source to destination using an auxiliary tower.
public void towerOfHanoi(int n, char source, char auxiliary, char destination) {
// Your implementation here
// Base case: Move one disk directly
// Recursive case: Move n-1 disks to auxiliary, then one to destination, then n-1 from auxiliary to destination
}