Skip to content

Review recursion #181

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions recursion/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
Recursion is a computational technique that implements a [divide-and-conquer](../dnc) approach to problem-solving by breaking down a complex problem into smaller sub-problems. It consists of two components:

* One or more base cases that provide output for simple inputs and terminate recursion
* A recursive case that combines the outputs obtained from recursive function calls to generate a solution for the original problem.
* A recursive case that combines the outputs obtained from recursive function calls to generate a solution for the original problem

Although recursions enhance code readability, they are usually inefficient and challenging to debug. Consequently, unless they provide a more efficient solution to a problem, such as in the case of [quicksort](../dnc/quick_sort_test.go), they are generally not preferred.

During execution, a program typically stores function variables in a memory area known as the stack before executing recursion. The recursive function may assign different values to the same variables during each recursion. When the recursion ends, the stack pops and remembers the values. However, the stack will grow with each call if recursion continues indefinitely, causing the familiar stack overflow error. Since recursion employs the stack to execute, every recursive problem can be converted into an iterative one. This transformation, however, typically leads to more complex code and may require a [stack](../stack).
During execution, a program typically stores function variables in a memory area known as the stack before executing recursion. The recursive function may assign different values to the same variables that are stored separately for each call during each recursion. When the recursion ends, the stack pops and remembers the values. However, the stack will grow with each call if recursion continues indefinitely, causing the familiar stack overflow error. Since recursion employs the stack to execute, every recursive problem can be converted into an iterative one. This transformation, however, typically leads to more complex code and may require a [stack](../stack).

## Implementation

Expand All @@ -16,9 +16,7 @@ The computation of the nth Fibonacci number can be achieved with recursion. For
```Go
package main

import (
"fmt"
)
import "fmt"

func main() {
for i := 1; i <= 10; i++ {
Expand All @@ -37,8 +35,8 @@ func fibonacci(n int) int {
When formulating recursive algorithms, it is essential to consider the following four rules of recursion:

1. It is imperative to establish a base case, or else the program will terminate abruptly
2. The algorithm should progress toward the base case at each recursive call.
3. Recursive calls are presumed effective; thus, traversing every recursive call and performing bookkeeping is unnecessary.
2. The algorithm should progress toward the base case at each recursive call
3. Recursive calls are presumed effective; thus, traversing every recursive call and performing bookkeeping is unnecessary
4. Use memoization, a technique that prevents redundant computation by caching previously computed results, can enhance the algorithm's efficiency.

## Complexity
Expand Down
13 changes: 13 additions & 0 deletions recursion/climbing_stairs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ TestClimbingStairs tests solution(s) with the following signature and problem de

Given n the number of steps, return in how many ways you can climb these stairs if you are
only able to climb 1 or 2 steps at a time.

For example given 5 we can climb the stairs in the following ways:

1, 1, 1, 1, 1
1, 1, 1, 2
1, 1, 2, 1
1, 2, 1, 1
2, 1, 1, 1
2, 2, 1,
1, 2, 2,
2, 1, 2,

So the algorithm should return 8.
*/
func TestClimbingStairs(t *testing.T) {
tests := []struct {
Expand Down
2 changes: 2 additions & 0 deletions recursion/exponentiation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ TestPowerOf tests solution(s) with the following signature and problem descripti
func PowerOf(x, n int) int

Given x and n, return x raised to the power of n in an efficient manner.

For example given x=2 and n=3 the algorithm should return 8.
*/
func TestPowerOf(t *testing.T) {
tests := []struct {
Expand Down
4 changes: 2 additions & 2 deletions recursion/expression_operators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ TestExpressionOperators tests solution(s) with the following signature and probl

func ExpressionOperators(list []int, target int) string

Given a list of numbers representing operands in an equation, and a target integer representing
Given a slice of numbers representing operands in an equation, and a target integer representing
the result of the equation, return a string representing operators that can be inserted between
the operands to form the equation and yield the target result.
Only + and - operators are allowed and the are assumed to have the same priority

For example given {1,5,3} and 3, return +- because 1+5-3 = 3.
For example given {1,5,3} and 3 return {+,-} because 1+5-3 = 3.
*/
func TestExpressionOperators(t *testing.T) {
tests := []struct {
Expand Down
4 changes: 3 additions & 1 deletion recursion/is_palindrome_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ TestIsPalindrome tests solution(s) with the following signature and problem desc

func IsPalindrome(s string) bool

Given a string like `abba` return true if it's a palindrome and false otherwise.
Given a string return true if it's a palindrome and false otherwise.

For example given `abba` return true. Given `abca` return false.
*/
func TestIsPalindrome(t *testing.T) {
tests := []struct {
Expand Down
2 changes: 2 additions & 0 deletions recursion/multiplication_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ TestMultiplication tests solution(s) with the following signature and problem de

Given two integers, return their product using recursion and without using the
multiplication operator.

For example given 2 and 3 return 6.
*/
func TestMultiplication(t *testing.T) {
tests := []struct {
Expand Down
4 changes: 4 additions & 0 deletions recursion/regular_expression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ Given an input and a regular expression pattern where
`*` denotes to zero or more of the proceeding characters

Write a recursive function to return true if the input matches the pattern and false otherwise.

For example given input `aa` and pattern `a*` the algorithm should return true, but given the same
pattern and "ba" it should return false.
*/
func TestRegularExpressions(t *testing.T) {
tests := []struct {
Expand All @@ -27,6 +30,7 @@ func TestRegularExpressions(t *testing.T) {
{"aa", "*", false},
{"aa", "*a", false},
{"aa", "a*", true},
{"ba", "a*", false},
{"aa", ".", false},
{"ab", ".", false},
{"ad", "d", false},
Expand Down
6 changes: 4 additions & 2 deletions recursion/reverse_number_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ TestReverseDigits tests solution(s) with the following signature and problem des

func ReverseDigits(n int) int

Given an integer like 321 return a reversed number using recursion where the same digits
are repeated in the reverse order like 321.
Given an integer reverse the order of the digits.

For example given 123 return 321.
*/
func TestReverseDigits(t *testing.T) {
tests := []struct {
Expand All @@ -19,6 +20,7 @@ func TestReverseDigits(t *testing.T) {
{12, 21},
{112, 211},
{110, 11},
{123, 321},
}

for i, test := range tests {
Expand Down