杨辉三角 II 图解题解
这道题到底在问什么
- rowIndex
- 4
- 输出
- [1,4,6,4,1]
- 解释
- 第 0 行 [1],逐行往下推,第 4 行就是 [1,4,6,4,1]
最优解:一步一步想明白
- 3存整张三角要 O(rowIndex²) 空间。可我们只要最后一行,前面的行算完就没用了——这就是优化的突破口:能不能只留一行?
- 4关键是从右往左更新。新值 row[j] 需要旧的左肩 row[j-1]——只要先动右边、后动左边,左边还没被改,读到的就是旧值,一个数组就够了。
- 5若从左往右:先把 row[1] 改了,等算 row[2]=row[2]+row[1] 时,row[1] 已是新值,污染了结果。从右往左则保证每次读到的左肩都还是上一行的旧值。
- 6只激活第 0 格我们开一个长度 5 的数组(rowIndex+1)。一开始只有第 0 格 = 1,代表第 0 行 [1]。灰色格子是后面才会激活的位置,盯住它们怎么一格格点亮、被填出数来。
- 7激活 slot 1 = 1往下推一行,先在末尾补个 1(杨辉三角每行最右都是 1)。现在数组前两格是 [1,1] = 第 1 行。第 1 行中间没有要加的数,直接成形。
- 8激活 slot 2 = 1推第 2 行,再在末尾补 1,暂时是 [1,1,1]。但中间那个 1 还不对——它该等于上一行的左肩+右肩。下面从右往左修它。
- 91 + 1 = 2更新 row[1]:它加上左边的 row[0]=1,从 1 变 2。第 2 行成形 = [1,2,1]。注意此时 row[0] 还是旧的 1,没被动过。
- 10激活 slot 3 = 1推第 3 行,末尾补 1,临时是 [1,2,1,1]。中间两个数(下标 2、1)要修。先修右边的 row[2],再修 row[1]——顺序不能反。
- 111 + 2 = 3先更右边的 row[2]:加上左肩 row[1]=2(还是旧值!),变成 3。此刻 row[1] 仍是 2,等下一步才轮到它。
- 122 + 1 = 3再更 row[1]:加上 row[0]=1 变 3。第 3 行成形 = [1,3,3,1]。看,右边先改完左边才改,左肩读到的一直是旧值,没被污染。
- 13激活 slot 4 = 1推到第 4 行(目标行),末尾补最后一个 1,临时是 [1,3,3,1,1]。所有格子都激活了。接下来从右往左更新下标 3、2、1 三个数。
- 141 + 3 = 4最右先动 row[3]:加上左肩 row[2]=3,变 4。继续往左。
- 153 + 3 = 6row[2] 加上左肩 row[1]=3(仍是旧值),变 6——这就是 [1,4,6,4,1] 正中间那个 6。
- 163 + 1 = 4最后更 row[1]:加 row[0]=1 变 4。数组定格为 [1,4,6,4,1]——这就是第 4 行答案!整个过程只用了一个数组。
- 17答案 = [1,4,6,4,1]整个过程只用了一行数组,没存任何中间行。空间从 O(n²) 压到 O(n),和题目要求对上了。
- 18下面用一张三角表把刚才的滚动还原成整张杨辉三角,逐格填一遍,你会更清楚每个数是怎么从上一行加出来的。
- 19T[0][0] = 1把三角左对齐放进表格。第 0 行只有一个 1。注意每行左右两端都是 1,中间靠相加得来。
- 20两端都是 1第 1 行 = [1,1],全是两端的 1。
- 21两端 = 1,中间待填每行先把两端的 1 摆好(下标 0 和末尾),中间留空。下一步算中间。
- 22T[2][1] = T[1][0]+T[1][1]第 2 行中间那个数 = 上一行的左肩 1 + 右肩 1 = 2。所以第 2 行 = [1,2,1],正好对上滚动数组里那一步。
- 23两端 = 1第 3 行先摆两端的 1,中间两个空位等着由上一行 [1,2,1] 相邻相加。
- 24[1,3,3,1]第 3 行中间两个数都由上一行 [1,2,1] 相邻相加得来:1+2=3、2+1=3。第 3 行 = [1,3,3,1]。
- 25两端 = 1最后一行(答案行)先摆两端 1,中间留三个空位,由上一行 [1,3,3,1] 相邻相加填出。
- 26[1,4,6,4,1]第 4 行由上一行 [1,3,3,1] 相邻相加:1+3=4、3+3=6、3+1=4,两端补 1,得 [1,4,6,4,1]。和滚动数组算出的完全一致——这就是答案。
⚠️ 容易写错的地方
✗ 错:内层从左往右更新
✓ 对:必须从右往左(j 递减)
从左往右会先改了左肩,右边再读就是新值,结果污染
✗ 错:再开一个新数组存当前行
✓ 对:在同一数组上原地更新
开新数组就退化成 O(n²) 空间,丢了本题考点
✗ 错:内层循环边界写成 j>=0
✓ 对:j 到 1 即止(row[0] 永远是 1)
j=0 时没有左肩 row[-1],且两端恒为 1 不该改
完整代码(Python / C++ / Java)
Python
class Solution:
def getRow(self, rowIndex):
row = [1] * (rowIndex + 1) # 一维数组,先全填 1
for i in range(2, rowIndex + 1): # 从第 2 行开始往下推
for j in range(i - 1, 0, -1): # 从右往左更新中间
row[j] += row[j - 1] # 当前 += 左肩(还是旧值)
return rowC++
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<int> row(rowIndex + 1, 1); // 一维数组,全填 1
for (int i = 2; i <= rowIndex; i++) {
for (int j = i - 1; j >= 1; j--) { // 从右往左
row[j] += row[j - 1];
}
}
return row;
}
};Java
class Solution {
public List<Integer> getRow(int rowIndex) {
int[] row = new int[rowIndex + 1];
Arrays.fill(row, 1); // 一维数组,全填 1
for (int i = 2; i <= rowIndex; i++) {
for (int j = i - 1; j >= 1; j--) { // 从右往左
row[j] += row[j - 1];
}
}
List<Integer> ans = new ArrayList<>();
for (int v : row) ans.add(v);
return ans;
}
}复杂度
时间复杂度
O(rowIndex²)
外层逐行、内层逐列,总更新次数约是三角形面积
空间复杂度
O(rowIndex)
只用一个长 rowIndex+1 的数组,没存整张三角
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 杨辉三角 II 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么一个数组就够,不会算错?+
因为新值 row[j] 只依赖旧的 row[j-1](左肩)和它自己(右肩)。从右往左更新,保证更新到 j 时左肩 j-1 还没动,仍是旧值,所以原地覆盖安全。
能不能用组合数 O(rowIndex) 时间直接算?+
能。第 k 个数 = C(rowIndex, k),用递推 C(n,k)=C(n,k-1)×(n-k+1)/k 顺序乘出来,一遍 O(rowIndex)、空间也 O(rowIndex),比逐行推更快。
和杨辉三角 I(返回整张三角)有什么区别?+
I 要返回所有行,必然 O(n²) 空间;II 只要某一行,才有机会用滚动数组压到 O(n)。这正是 II 的考点。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 杨辉三角 II 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。