题目描述
给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。在「杨辉三角」中,每个数是它左上方和右上方的数的和。
示例 1:
输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
杨辉三角:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
示例 2:
输入: numRows = 1
输出: [[1]]
提示:
- 1 <= numRows <= 30
解题思路总览
| 方法 | 思路 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|---|
| 模拟构造 | 模拟杨辉三角生成规则,第 i 行有 i 个元素 | O(n^2) | O(n^2) | 面试首选 |
核心原理: 杨辉三角的第 i 行第 j 个元素 = 第 i-1 行第 j-1 个元素 + 第 i-1 行第 j 个元素(j 从 1 开始)
模拟构造(推荐)
思路
根据杨辉三角的性质直接模拟:
- 第 i 行有 i 个元素(行号从 0 开始)
- 每行的第一个和最后一个元素都是 1
- 中间的元素
triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j]
完整代码
cpp
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> ans;
for (int i = 0; i < numRows; i++) {
vector<int> temp;
if (i == 0) {
ans.push_back({1});
continue;
}
for (int j = 0; j <= i; j++) {
if (j == 0 || j == i) {
temp.push_back(1); // 首尾元素为 1
} else {
// 中间元素 = 左上方 + 右上方
temp.push_back(ans[i-1][j-1] + ans[i-1][j]);
}
}
ans.emplace_back(temp);
}
return ans;
}
};
算法流程图
以 numRows = 5 为例:
构建过程:
i = 0:
temp = [1]
ans = [[1]]
i = 1:
j = 0: j==0 → temp=[1]
j = 1: j==i → temp=[1,1]
ans = [[1], [1,1]]
i = 2:
j = 0: j==0 → temp=[1]
j = 1: j!=0 && j!=i → temp=[1, 1+1=2]
j = 2: j==i → temp=[1,2,1]
ans = [[1], [1,1], [1,2,1]]
i = 3:
j = 0: → temp=[1]
j = 1: → temp=[1, 1+2=3]
j = 2: → temp=[1,3, 2+1=3]
j = 3: → temp=[1,3,3,1]
ans = [[1], [1,1], [1,2,1], [1,3,3,1]]
i = 4:
j = 0: → temp=[1]
j = 1: → temp=[1, 1+3=4]
j = 2: → temp=[1,4, 3+3=6]
j = 3: → temp=[1,4,6, 3+1=4]
j = 4: → temp=[1,4,6,4,1]
ans = [[1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1]]
最终返回 ans
逐行解析
cpp
vector<vector<int>> ans;
- 二维向量,存储杨辉三角的所有行。
cpp
for (int i = 0; i < numRows; i++) {
vector<int> temp;
if (i == 0) {
ans.push_back({1});
continue;
}
- 外层循环遍历每一行。
- 第 0 行特殊处理,直接添加
[1]。
cpp
for (int j = 0; j <= i; j++) {
if (j == 0 || j == i) {
temp.push_back(1); // 首尾元素为 1
} else {
temp.push_back(ans[i-1][j-1] + ans[i-1][j]);
}
}
- 内层循环遍历当前行的每个元素。
j == 0 || j == i:首尾元素,直接添加 1。- 否则:
ans[i-1][j-1] + ans[i-1][j],当前元素等于上一行的左上方 + 右上方。
cpp
ans.emplace_back(temp);
- 将当前行添加到结果中。
复杂度分析
| 复杂度 | 值 | 说明 |
|---|---|---|
| 时间 | O(n^2) | 遍历半个三角,n 行共约 n*(n+1)/2 个元素 |
| 空间 | O(n^2) | 存储所有元素 |
优点: 思路直接,代码清晰
缺点: 无
杨辉三角的性质
| 性质 | 说明 |
|---|---|
| 对称性 | 第 i 行有 i 个元素,首尾都是 1 |
| 组合数 | 第 i 行第 j 列 = C(i, j)(二项式系数) |
| 求和 | 第 n 行元素之和 = 2^n |
| 斐波那契 | 杨辉三角的斜线之和构成斐波那契数列 |
杨辉三角中的组合数:
C(0,0) = 1
C(1,0)=1, C(1,1)=1
C(2,0)=1, C(2,1)=2, C(2,2)=1
C(3,0)=1, C(3,1)=3, C(3,2)=3, C(3,3)=1
...
面试追问 FAQ
| 问题 | 解答 |
|---|---|
Q1:为什么 ans[i-1][j-1] + ans[i-1][j] 能得到正确元素? |
这是杨辉三角的定义:每个数是它左上方和右上方的数之和。在数组表示中,ans[i-1][j-1] 是左上方,ans[i-1][j] 是右上方。 |
Q2:为什么内层循环是 j <= i? |
因为第 i 行(从 0 开始计数)恰好有 i+1 个元素,所以 j 从 0 到 i,共 i+1 次。 |
| Q3:杨辉三角和二项式系数有什么关系? | 杨辉三角的第 n 行第 k 列(从 0 开始)恰好等于 C(n, k),即二项式展开的系数。这就是二项式定理的可视化表示。 |
| Q4:如果要返回第 numRows 行的第 k 个元素,怎么优化? | 直接用组合数公式 C(n, k) = n! / (k! * (n-k)!),不需要生成整个三角。 |
| Q5:能否用更简洁的代码实现? | 可以合并一些逻辑,但基本框架不变。核心是 triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j]。 |
相关题目
| 题目 | 难度 | 关键点 |
|---|---|---|
| 118. 杨辉三角 | 简单 | 模拟构造 |
| 119. 杨辉三角 II | 简单 | 只返回某一行 |
| 剑指 Offer 62. 圆圈中最后剩下的数字 | 简单 | 杨辉三角性质(约瑟夫环) |
总结
| 要点 | 说明 |
|---|---|
| 核心原理 | triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j] |
| 首尾元素 | 每行首尾都是 1 |
| 时间复杂度 | O(n^2) |
| 空间复杂度 | O(n^2) |