Java ProgramsNumbersFind Nth Catalan Number

Find Nth Catalan Number in Java

advanced·  Numbers  ·  Combinatorics

Problem

The Nth Catalan number counts things like the number of ways to arrange balanced parentheses or the number of distinct binary search trees with n nodes, and can be built up from smaller Catalan numbers.

Given a number n, find the Nth Catalan number.

Input
4
Output
Catalan number at n = 4: 14

Java Program

Java
public class NthCatalanNumber { public static void main(String[] args) { int n = 4; long[] catalan = new long[n + 1]; catalan[0] = 1; // base case of the sequence for (int i = 1; i <= n; i++) { long sum = 0; for (int j = 0; j < i; j++) { sum += catalan[j] * catalan[i - 1 - j]; // pairs of already-known smaller Catalan numbers } catalan[i] = sum; } System.out.println("Catalan number at n = " + n + ": " + catalan[n]); } }

Output

Catalan number at n = 4: 14

Core Logic

Building every Catalan number from 0 up to n, using the recurrence that defines each one in terms of all the smaller ones, avoids recomputing the same smaller values over and over.

How It Works
  1. 1catalan[0] is set to 1, the base case of the sequence.
  2. 2Each subsequent catalan[i] is built from every pair of already-known smaller Catalan numbers: catalan[j] * catalan[i - 1 - j], summed over every j from 0 to i - 1.
  3. 3This mirrors the mathematical recurrence C(i) = Σ C(j) × C(i-1-j), which is exactly how the Catalan sequence is defined.
  4. 4By the time the outer loop reaches i = n, every smaller Catalan number it depends on has already been computed and stored.
For n = 4, the sequence builds up as 1, 1, 2, 5, 14 — each new value computed entirely from the ones before it.
💡

Key Point: This is the same idea as memoized Fibonacci — instead of recomputing smaller Catalan numbers from scratch every time they're needed, each one is calculated once and reused.

Complexity
Time Complexity: O(n²)Space Complexity: O(n)

Why: Building each Catalan number requires summing over all smaller pairs, so the nested loops do O(n²) work while the array holds n + 1 running values.

Key Concepts

dynamic programmingrecurrence relationarray

Approach 2: Binomial Coefficient Formula

Java
public class NthCatalanNumberFormula { public static void main(String[] args) { int n = 4; long binomial = 1; // Builds C(2n, n) iteratively using the multiplicative formula for binomial coefficients for (int i = 0; i < n; i++) { binomial = binomial * (2L * n - i) / (i + 1); } long catalan = binomial / (n + 1); System.out.println("Catalan number at n = " + n + ": " + catalan); } }

Output

Catalan number at n = 4: 14

Core Logic

The Nth Catalan number also has a direct closed-form formula — C(2n, n) divided by (n + 1) — which sidesteps the recurrence entirely.

How It Works
  1. 1binomial builds up C(2n, n) using the same multiplicative formula the combination program uses, one factor at a time.
  2. 2Multiplying before dividing at each step keeps every intermediate value an exact integer, avoiding the need for factorials of very large numbers.
  3. 3Once C(2n, n) is known, dividing it by n + 1 gives the Catalan number directly.
  4. 4No array or recurrence is needed — the whole computation is a single loop of n multiplications and divisions.
For n = 4, the loop builds C(8, 4) = 70, and 70 / (4 + 1) = 14 — the same answer the DP table found.
💡

Key Point: This trades the DP table's O(n) space for O(1) space, at the cost of needing to know (or derive) the binomial-coefficient identity in the first place.

Complexity
Time Complexity: O(n)Space Complexity: O(1)

Why: The binomial coefficient is built up with a single loop of n multiplications and divisions, and only one running value is kept.

Key Concepts

binomial coefficientmultiplicative formulasingle loop

Approach 3: Java 8

Java
import java.util.stream.IntStream; public class NthCatalanNumberStream { public static void main(String[] args) { int n = 4; // Folds the binomial coefficient formula across each index, just like the loop version long binomial = IntStream.range(0, n) .mapToObj(i -> i) .reduce(1L, (acc, i) -> acc * (2L * n - i) / (i + 1), (a, b) -> a * b); long catalan = binomial / (n + 1); System.out.println("Catalan number at n = " + n + ": " + catalan); } }

Output

Catalan number at n = 4: 14

Core Logic

The binomial-coefficient loop is a running product-and-divide carried from one iteration to the next — exactly the shape a stream fold expresses with reduce().

How It Works
  1. 1IntStream.range(0, n).mapToObj(i -> i) turns the loop's index range into a Stream&lt;Integer&gt;, since IntStream itself has no three-argument reduce().
  2. 2.reduce(1L, (acc, i) -> acc * (2L * n - i) / (i + 1), (a, b) -> a * b) folds the running binomial value across every index, the same multiply-then-divide each iteration performed.
  3. 3The identity 1L and the accumulator lambda reproduce the loop's starting value and per-step update exactly; the combiner is required by this reduce() overload but never actually runs, since the stream here is sequential.
  4. 4Dividing the folded result by n + 1 afterward gives the Catalan number, same as the loop-based version.
For n = 4, folding across indices 0, 1, 2, 3 builds the binomial coefficient up to 70, and 70 / 5 = 14.
💡

Key Point: reduce() is the stream vocabulary for exactly this pattern — 'combine a running value with each element' — which is what the imperative loop was already doing one line at a time.

Complexity
Time Complexity: O(n)Space Complexity: O(1)

Why: The fold still performs one multiplication and division per index from 0 to n, carrying only a single running value forward.

Key Concepts

Stream.reduce()foldIntStream

Related Programs