Skip to content

Commit c694ed1

Browse files
committed
Add catalan_numbers.py
1 parent b913a0d commit c694ed1

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
"""
2+
Print all the Catalan numbers from 0 to n, n being the user input.
3+
4+
* The Catalan numbers are a sequence of positive integers that
5+
* appear in many counting problems in combinatorics [1]. Such
6+
* problems include counting [2]:
7+
* - The number of Dyck words of length 2n
8+
* - The number well-formed expressions with n pairs of parentheses
9+
* (e.g., `()()` is valid but `())(` is not)
10+
* - The number of different ways n + 1 factors can be completely
11+
* parenthesized (e.g., for n = 2, C(n) = 2 and (ab)c and a(bc)
12+
* are the two valid ways to parenthesize.
13+
* - The number of full binary trees with n + 1 leaves
14+
15+
* A Catalan number satisfies the following recurrence relation
16+
* which we will use in this algorithm [1].
17+
* C(0) = C(1) = 1
18+
* C(n) = sum(C(i).C(n-i-1)), from i = 0 to n-1
19+
20+
* In addition, the n-th Catalan number can be calculated using
21+
* the closed form formula below [1]:
22+
* C(n) = (1 / (n + 1)) * (2n choose n)
23+
24+
* Sources:
25+
* [1] https://brilliant.org/wiki/catalan-numbers/
26+
* [2] https://en.wikipedia.org/wiki/Catalan_number
27+
"""
28+
29+
30+
class Catalan:
31+
def __init__(self, upper_limit: int) -> None:
32+
"""
33+
Create an object with a list of Catalan
34+
numbers from 0 through upper_limit
35+
"""
36+
self.catalan_numbers = [0] * (upper_limit + 1)
37+
if upper_limit:
38+
# Base case: C(0) = C(1) = 1
39+
self.catalan_numbers[0] = 1
40+
self.catalan_numbers[1] = 1
41+
42+
# Recurrence relation: C(i) = sum(C(j).C(i-j-1)), from j = 0 to i
43+
for i in range(2, upper_limit + 1):
44+
for j in range(i):
45+
self.catalan_numbers[i] += (
46+
self.catalan_numbers[j] * self.catalan_numbers[i - j - 1]
47+
)
48+
elif upper_limit == 0:
49+
self.catalan_numbers[0] = 1
50+
print(self.catalan_numbers)
51+
52+
def get(self, sequence_no: int) -> None:
53+
"""
54+
>>> Catalan(5).get(3)
55+
[1, 1, 2, 5, 14, 42]
56+
[1, 1, 2, 5]
57+
>>> Catalan(5).get(6)
58+
[1, 1, 2, 5, 14, 42]
59+
Out of bound.
60+
>>> Catalan(5).get(-1)
61+
[1, 1, 2, 5, 14, 42]
62+
[]
63+
"""
64+
if sequence_no is not None:
65+
if sequence_no < len(self.catalan_numbers):
66+
return print(self.catalan_numbers[: sequence_no + 1])
67+
else:
68+
print("Out of bound.")
69+
else:
70+
print("Please specify a value")
71+
72+
73+
if __name__ == "__main__":
74+
print("\n********* Catalan Numbers Using Dynamic Programming ************\n")
75+
print("\n Enter the upper limit for the Catalan number sequence: ", end="")
76+
try:
77+
N = int(input().strip())
78+
if N < 0:
79+
print("\nInput must be ≥ 0, please try again.")
80+
else:
81+
cat = Catalan(N)
82+
print(
83+
"\n********* Enter different values to get the corresponding Catalan "
84+
"Number sequence, enter any negative number to exit. ************\n"
85+
)
86+
while True:
87+
try:
88+
i = int(input("Enter value: ").strip())
89+
if i < 0:
90+
print("\n********* Good Bye!! ************\n")
91+
break
92+
cat.get(i)
93+
except NameError:
94+
print("\nInvalid input, please try again.")
95+
except (NameError, ValueError):
96+
print("\n********* Invalid input, good bye!! ************\n")
97+
98+
import doctest
99+
100+
doctest.testmod()

0 commit comments

Comments
 (0)