118. Pascals Triangle - Explanation

Problem Link

Description

You are given an integer numRows, return the first numRows of Pascal's triangle.

In Pascal's triangle, each number is the sum of the two numbers directly above it as shown:

Example 1:

Input: numRows = 5

Output: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]

Example 2:

Input: numRows = 1

Output: [[1]]

Constraints:

  • 1 <= numRows <= 30


Topics

Company Tags

Please upgrade to NeetCode Pro to view company tags.



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Dynamic Programming - Building each row using values from the previous row
  • 2D Arrays - Storing and accessing the triangle structure
  • Combinatorics - Understanding that each element is a binomial coefficient C(n, k) and can be computed incrementally

1. Combinatorics

Intuition

Each element in Pascal's Triangle corresponds to a binomial coefficient. The value at row n and position k is C(n, k). Rather than computing each coefficient from scratch using factorials, we can compute them incrementally. Starting from 1, each subsequent value in a row can be derived by multiplying by (n - k + 1) / k.

Algorithm

  1. Initialize an empty result list.
  2. For each row n from 0 to numRows - 1:
    • Start the row with [1].
    • Set val = 1.
    • For each position k from 1 to n:
      • Compute val = val * (n - k + 1) / k.
      • Append val to the row.
    • Add the completed row to the result.
  3. Return the result list.
class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        res = []
        for n in range(numRows):
            row = [1]
            val = 1
            for k in range(1, n + 1):
                val = val * (n - k + 1) // k
                row.append(val)
            res.append(row)
        return res

Time & Space Complexity

  • Time complexity: O(n2)O(n ^ 2)
  • Space complexity: O(n2)O(n ^ 2)

2. Dynamic Programming - I

Intuition

Each element in Pascal's Triangle (except the edges) is the sum of the two elements directly above it. We can simulate this by padding the previous row with zeros on both ends, then summing adjacent pairs to generate the next row.

Algorithm

  1. Start with the first row [[1]].
  2. For each subsequent row:
    • Take the last row and pad it with zeros: [0] + row + [0].
    • Create a new row by summing adjacent elements: temp[j] + temp[j + 1].
    • Append the new row to the result.
  3. Return the result after generating numRows rows.
class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        res = [[1]]

        for i in range(numRows - 1):
            temp = [0] + res[-1] + [0]
            row = []
            for j in range(len(res[-1]) + 1):
                row.append(temp[j] + temp[j + 1])
            res.append(row)
        return res

Time & Space Complexity

  • Time complexity: O(n2)O(n ^ 2)
  • Space complexity: O(n2)O(n ^ 2)

3. Dynamic Programming - II

Intuition

We directly apply the defining property of Pascal's Triangle: each interior element equals the sum of the two elements above it. The first and last elements of every row are always 1. We build row by row, referencing the previous row for the sums.

Algorithm

  1. Initialize a 2D list where row i has i + 1 elements, all set to 1.
  2. For each row from index 2 onward:
    • For each interior position j (not the first or last):
      • Set res[i][j] = res[i - 1][j - 1] + res[i - 1][j].
  3. Return the completed triangle.
class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        res = [[1] * (i + 1) for i in range(numRows)]
        for i in range(2, numRows):
            for j in range(1, i):
                res[i][j] = res[i - 1][j - 1] + res[i - 1][j]
        return res

Time & Space Complexity

  • Time complexity: O(n2)O(n ^ 2)
  • Space complexity: O(n2)O(n ^ 2)

Common Pitfalls

Off-by-One Errors with Row Indexing

Pascal's Triangle is often 0-indexed, so row 0 is [1], row 1 is [1, 1], and so on. Confusing 0-indexed and 1-indexed row numbering leads to generating one too many or one too few rows. Always clarify whether numRows means the count of rows or the index of the last row.

Forgetting Edge Elements Are Always 1

The first and last elements of every row are always 1. When building rows iteratively, only the interior elements (positions 1 through i-1 for row i) need to be computed as sums. Attempting to compute edge elements using the sum formula causes index-out-of-bounds errors.