A clear explanation of generating Pascal's Triangle row by row using dynamic programming.
Problem Restatement
We are given an integer:
numRowsWe need to generate the first numRows rows of Pascal’s Triangle.
In Pascal’s Triangle:
- The first and last number of every row are
1. - Every interior value equals the sum of the two numbers directly above it.
The official problem asks us to return the first numRows rows. (leetcode.com)
For example:
numRows = 5The output is:
[
[1],
[1, 1],
[1, 2, 1],
[1, 3, 3, 1],
[1, 4, 6, 4, 1]
]Input and Output
| Item | Meaning |
|---|---|
| Input | Integer numRows |
| Output | First numRows rows of Pascal’s Triangle |
| Edge values | Always 1 |
| Interior values | Sum of two values above |
The function shape is:
class Solution:
def generate(self, numRows: int) -> list[list[int]]:
...Examples
For:
numRows = 1the triangle is:
[
[1]
]For:
numRows = 5the rows are built step by step.
Row 0:
[1]Row 1:
[1, 1]Row 2:
[1, 2, 1]because:
2 = 1 + 1Row 3:
[1, 3, 3, 1]because:
3 = 1 + 2
3 = 2 + 1First Thought: Build Rows One by One
Each row depends only on the previous row.
So instead of computing combinations directly, we can generate rows incrementally.
For every new row:
- Start with
1. - Compute interior values using the previous row.
- End with
1.
This naturally forms a dynamic programming process.
Key Insight
Suppose the previous row is:
[1, 3, 3, 1]The next row starts and ends with 1:
[1, ?, ?, ?, 1]Each interior value comes from the two values above:
1 + 3 = 4
3 + 3 = 6
3 + 1 = 4So the next row becomes:
[1, 4, 6, 4, 1]The rule is:
for interior positions.
Algorithm
Initialize:
ans = []For each row index i:
- Create a row filled with
1s of lengthi + 1. - For every interior position:
- Compute the sum of the two values above.
- Append the row to the answer.
Return the completed triangle.
Correctness
The algorithm builds the triangle row by row.
Each row begins and ends with 1, which matches the definition of Pascal’s Triangle.
For every interior position j, the algorithm computes:
These are exactly the two numbers directly above the current position in Pascal’s Triangle.
Therefore, every interior value is correct.
Since each row is built from the previous row using the Pascal recurrence rule, every generated row matches Pascal’s Triangle exactly.
Thus, after numRows iterations, the algorithm correctly returns the first numRows rows.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(numRows^2) | Every triangle value is computed once |
| Space | O(numRows^2) | The output stores all rows |
The output itself contains:
values.
Implementation
class Solution:
def generate(self, numRows: int) -> list[list[int]]:
ans = []
for i in range(numRows):
row = [1] * (i + 1)
for j in range(1, i):
row[j] = ans[i - 1][j - 1] + ans[i - 1][j]
ans.append(row)
return ansCode Explanation
The answer list stores all rows:
ans = []Each row has length:
i + 1Create the row initially filled with 1s:
row = [1] * (i + 1)The first and last values remain 1.
Now compute interior values:
for j in range(1, i):Use the previous row:
row[j] = ans[i - 1][j - 1] + ans[i - 1][j]Append the completed row:
ans.append(row)Finally:
return ansTesting
class Solution:
def generate(self, numRows: int) -> list[list[int]]:
ans = []
for i in range(numRows):
row = [1] * (i + 1)
for j in range(1, i):
row[j] = ans[i - 1][j - 1] + ans[i - 1][j]
ans.append(row)
return ans
def run_tests():
s = Solution()
assert s.generate(1) == [
[1]
]
assert s.generate(2) == [
[1],
[1, 1],
]
assert s.generate(5) == [
[1],
[1, 1],
[1, 2, 1],
[1, 3, 3, 1],
[1, 4, 6, 4, 1],
]
assert s.generate(6) == [
[1],
[1, 1],
[1, 2, 1],
[1, 3, 3, 1],
[1, 4, 6, 4, 1],
[1, 5, 10, 10, 5, 1],
]
print("all tests passed")
run_tests()Test meaning:
| Test | Why |
|---|---|
numRows = 1 | Minimum valid triangle |
numRows = 2 | Small base structure |
numRows = 5 | Standard example |
numRows = 6 | Confirms larger row generation |