Skip to content

Commit 2d1bfc4

Browse files
feat: add Catalan numbers implementation using dynamic programming (TheAlgorithms#961)
1 parent 1a27c6c commit 2d1bfc4

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
* [Union Find](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/union_find.rs)
8888
* [Veb Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/veb_tree.rs)
8989
* Dynamic Programming
90+
* [Catalan Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/catalan_numbers.rs)
9091
* [Coin Change](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/coin_change.rs)
9192
* [Egg Dropping](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/egg_dropping.rs)
9293
* [Fibonacci](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/fibonacci.rs)
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//! Catalan Numbers using Dynamic Programming
2+
//!
3+
//! The Catalan numbers are a sequence of positive integers that appear in many
4+
//! counting problems in combinatorics. Such problems include counting:
5+
//! - The number of Dyck words of length 2n
6+
//! - The number of well-formed expressions with n pairs of parentheses
7+
//! (e.g., `()()` is valid but `())(` is not)
8+
//! - The number of different ways n + 1 factors can be completely parenthesized
9+
//! (e.g., for n = 2, C(n) = 2 and (ab)c and a(bc) are the two valid ways)
10+
//! - The number of full binary trees with n + 1 leaves
11+
//!
12+
//! A Catalan number satisfies the following recurrence relation:
13+
//! - C(0) = C(1) = 1
14+
//! - C(n) = sum(C(i) * C(n-i-1)), from i = 0 to n-1
15+
//!
16+
//! Sources:
17+
//! - [Brilliant.org](https://brilliant.org/wiki/catalan-numbers/)
18+
//! - [Wikipedia](https://en.wikipedia.org/wiki/Catalan_number)
19+
20+
/// Computes the Catalan number sequence from 0 through `upper_limit`.
21+
///
22+
/// # Arguments
23+
///
24+
/// * `upper_limit` - The upper limit for the Catalan sequence (must be ≥ 0)
25+
///
26+
/// # Returns
27+
///
28+
/// A vector containing Catalan numbers from C(0) to C(upper_limit)
29+
///
30+
/// # Complexity
31+
///
32+
/// * Time complexity: O(n²)
33+
/// * Space complexity: O(n)
34+
///
35+
/// where `n` is the `upper_limit`.
36+
///
37+
/// # Examples
38+
///
39+
/// ```
40+
/// use the_algorithms_rust::dynamic_programming::catalan_numbers;
41+
///
42+
/// assert_eq!(catalan_numbers(5), vec![1, 1, 2, 5, 14, 42]);
43+
/// assert_eq!(catalan_numbers(2), vec![1, 1, 2]);
44+
/// assert_eq!(catalan_numbers(0), vec![1]);
45+
/// ```
46+
///
47+
/// # Warning
48+
///
49+
/// This will overflow the 64-bit unsigned integer for large values of `upper_limit`.
50+
/// For example, C(21) and beyond will cause overflow.
51+
pub fn catalan_numbers(upper_limit: usize) -> Vec<u64> {
52+
let mut catalan_list = vec![0u64; upper_limit + 1];
53+
54+
// Base case: C(0) = 1
55+
catalan_list[0] = 1;
56+
57+
// Base case: C(1) = 1
58+
if upper_limit > 0 {
59+
catalan_list[1] = 1;
60+
}
61+
62+
// Recurrence relation: C(i) = sum(C(j) * C(i-j-1)), from j = 0 to i-1
63+
for i in 2..=upper_limit {
64+
for j in 0..i {
65+
catalan_list[i] += catalan_list[j] * catalan_list[i - j - 1];
66+
}
67+
}
68+
69+
catalan_list
70+
}
71+
72+
#[cfg(test)]
73+
mod tests {
74+
use super::*;
75+
76+
#[test]
77+
fn test_catalan_numbers_basic() {
78+
assert_eq!(catalan_numbers(5), vec![1, 1, 2, 5, 14, 42]);
79+
assert_eq!(catalan_numbers(2), vec![1, 1, 2]);
80+
assert_eq!(catalan_numbers(0), vec![1]);
81+
}
82+
83+
#[test]
84+
fn test_catalan_numbers_single() {
85+
assert_eq!(catalan_numbers(1), vec![1, 1]);
86+
}
87+
88+
#[test]
89+
fn test_catalan_numbers_extended() {
90+
let result = catalan_numbers(10);
91+
assert_eq!(result.len(), 11);
92+
assert_eq!(result[0], 1);
93+
assert_eq!(result[1], 1);
94+
assert_eq!(result[2], 2);
95+
assert_eq!(result[3], 5);
96+
assert_eq!(result[4], 14);
97+
assert_eq!(result[5], 42);
98+
assert_eq!(result[6], 132);
99+
assert_eq!(result[7], 429);
100+
assert_eq!(result[8], 1430);
101+
assert_eq!(result[9], 4862);
102+
assert_eq!(result[10], 16796);
103+
}
104+
105+
#[test]
106+
fn test_catalan_first_few() {
107+
// Verify the first few Catalan numbers match known values
108+
assert_eq!(catalan_numbers(3), vec![1, 1, 2, 5]);
109+
assert_eq!(catalan_numbers(4), vec![1, 1, 2, 5, 14]);
110+
}
111+
}

src/dynamic_programming/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod catalan_numbers;
12
mod coin_change;
23
mod egg_dropping;
34
mod fibonacci;
@@ -22,6 +23,7 @@ mod task_assignment;
2223
mod trapped_rainwater;
2324
mod word_break;
2425

26+
pub use self::catalan_numbers::catalan_numbers;
2527
pub use self::coin_change::coin_change;
2628
pub use self::egg_dropping::egg_drop;
2729
pub use self::fibonacci::binary_lifting_fibonacci;

0 commit comments

Comments
 (0)