Skip to content

Commit c018648

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

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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, N: int):
32+
self.catalan_numbers = [0] * (N + 1)
33+
if N:
34+
N = int(N)
35+
# Base case: C(0) = C(1) = 1
36+
self.catalan_numbers[0] = 1
37+
self.catalan_numbers[1] = 1
38+
39+
# Recurrence relation: C(i) = sum(C(j).C(i-j-1)), from j = 0 to i
40+
for i in range(2, N + 1):
41+
for j in range(i):
42+
self.catalan_numbers[i] += (
43+
self.catalan_numbers[j] * self.catalan_numbers[i - j - 1]
44+
)
45+
elif N == 0:
46+
self.catalan_numbers[0] = 1
47+
print(self.catalan_numbers)
48+
49+
def get(self, sequence_no=None):
50+
"""
51+
>>> Catalan(5).get(3)
52+
[1, 1, 2, 5, 14, 42]
53+
[1, 1, 2, 5]
54+
>>> Catalan(5).get(6)
55+
[1, 1, 2, 5, 14, 42]
56+
Out of bound.
57+
>>> Catalan(5).get(-1)
58+
[1, 1, 2, 5, 14, 42]
59+
[]
60+
"""
61+
if sequence_no is not None:
62+
if sequence_no < len(self.catalan_numbers):
63+
return print(self.catalan_numbers[: sequence_no + 1])
64+
else:
65+
print("Out of bound.")
66+
else:
67+
print("Please specify a value")
68+
69+
70+
if __name__ == "__main__":
71+
print("\n********* Catalan Numbers Using Dynamic Programming ************\n")
72+
print("\n Enter the upper limit for the Catalan number sequence: ", end="")
73+
try:
74+
N = int(input().strip())
75+
cat = Catalan(N)
76+
print(
77+
"\n********* Enter different values to get the corresponding Catalan "
78+
"Number sequence, enter any negative number to exit. ************\n"
79+
)
80+
while True:
81+
try:
82+
i = int(input("Enter value: ").strip())
83+
if i < 0:
84+
print("\n********* Good Bye!! ************\n")
85+
break
86+
cat.get(i)
87+
except NameError:
88+
print("\nInvalid input, please try again.")
89+
except NameError:
90+
print("\n********* Invalid input, good bye!! ************\n")
91+
92+
import doctest
93+
94+
doctest.testmod()

0 commit comments

Comments
 (0)