Skip to article
ALGORITHMICSDSA / Arrays
DSAeasy5 min read

Pascal's Triangle

Each row from the one above it — the smallest dynamic programming table there is.


Build the first numRows rows. Every row starts and ends with 1, and every interior cell is the sum of the two above it.

1
1 1
1 2 1
1 3 3 1
1 4 6 4 1

Straight from the definition

1 / 11
1

Row 1 is closed with a 1. Every row starts and ends with one, which is why the inner loop only ever fills the middle.

func generate(numRows int) [][]int {
var result = [][]int{}
result = append(result, []int{1})
for i := 1; i < numRows; i++ {
var row = []int{}
row = append(row, 1)
for j := 1; j < i; j++ {
row = append(row, result[i-1][j-1]+result[i-1][j])
}
row = append(row, 1)
result = append(result, row)
}
return result
}

O(numRows2)O(numRows^2) time and output — which is optimal, because that is how many numbers there are.

The edges, and why the loop skips them

The inner loop runs j from 1 to i-1 — never touching the ends. Those are appended unconditionally instead, because T[i-1][j-1] and T[i-1][j] do not both exist at the boundary.

That is the usual DP shape: a recurrence for the interior, base cases for the edges. Trying to make one expression cover both means bounds-checking on every cell.

Preallocating

Each row’s length is known before it is built — row i has i+1 entries — so the appends can be replaced with an allocation:

func generate(numRows int) [][]int {
result := make([][]int, numRows)
for i := range result {
row := make([]int, i+1)
row[0], row[i] = 1, 1
for j := 1; j < i; j++ {
row[j] = result[i-1][j-1] + result[i-1][j]
}
result[i] = row
}
return result
}

Same complexity, no reallocation as the rows grow, and it handles numRows = 0 correctly for free — make([][]int, 0) and a loop that never runs. Knowing the size up front is the same habit that concatenation of array is really about.

Pascal’s Triangle II asks for row k alone, in O(k)O(k) space. You can build it in place if you fill right to left, so each cell is updated before the value it depends on is overwritten. Left to right destroys T[i-1][j-1] before you use it — the same read-before-write ordering as the in-place suffix walk in replace elements.

Any single entry is (ij)\binom{i}{j}, computable directly without the table at all. The triangle is only the efficient route when you want many entries.