LeetCode 119. 杨辉三角 II
题目描述



题意分析
给一个行号
rowIndex,只要返回杨辉三角的这一行,前面的行不必输出。行号从 0 开始计数,第 0 行是[1],第 1 行是[1, 1],第 3 行是[1, 3, 3, 1],所以第rowIndex行恰好有rowIndex + 1个数。三角形的构造规则是:每行首尾都是 1,中间每个位置等于它正上方与左上方两个数之和。注意这条规则只跨越相邻两行,第
i行完全由第i - 1行决定,与更早的行无关。「只要一行」是本题相对上一道题最关键的差异,也是空间优化的入口。题目进阶还要求只用
O(rowIndex)的额外空间,等于明说不能把整个三角形都存下来。边界方面,rowIndex可以取 0,此时答案是单个 1;行号上限在三十出头,最大的那个数不会超过 32 位整数范围,不必担心溢出。
解法:组合数递推
核心思路
问题关键: 第
k行的第j个数就是组合数C(k,j)。既然只要一行,就没有必要构造前面的所有行。相邻组合数满足:
\[C(k,0)=1,\qquad C(k,j+1)=C(k,j)\times\frac{k-j}{j+1}\]因此从 1 开始即可按顺序推出整行。相比一维逆序动态规划的 $O(k^2)$ 时间,组合数递推只需 $O(k)$ 时间。
正确性: 初值是
C(k,0)。若当前值为C(k,j),根据组合数定义约去公共阶乘后,递推式计算出的下一项恰为C(k,j+1);由归纳法,写入的k+1项全部正确。溢出处理: 题目范围内最终系数能放入 32 位整数,但“当前系数乘以
k-j”的中间结果可能超出 32 位,所以先用 64 位完成乘法和除法,再转换为结果类型。
解题步骤
- 创建长度为
rowIndex + 1的结果,令当前组合数value = 1。- 从
j = 0到rowIndex,先写入当前的C(rowIndex,j)。- 用
value = value * (rowIndex - j) / (j + 1)推出下一项。- 返回结果。
口述示例:
rowIndex = 4时,从 1 开始依次乘除:1 -> 4 -> 6 -> 4 -> 1,得到[1,4,6,4,1]。边界:
rowIndex = 0时只写入初值 1。每一步的数学结果都是整数,但必须先乘后除;提前做整数除法会截断。
代码实现
import java.util.ArrayList;
import java.util.List;
class Solution {
public List<Integer> getRow(int rowIndex) {
List<Integer> row = new ArrayList<>(rowIndex + 1);
long value = 1;
for (int j = 0; j <= rowIndex; j++) {
row.add((int) value);
value = value * (rowIndex - j) / (j + 1);
}
return row;
}
}
func getRow(rowIndex int) []int {
row := make([]int, rowIndex+1)
value := int64(1)
for j := 0; j <= rowIndex; j++ {
row[j] = int(value)
value = value * int64(rowIndex-j) / int64(j+1)
}
return row
}
复杂度分析
- 时间复杂度:$O(k)$,其中
k = rowIndex,每个结果只计算一次。- 空间复杂度:$O(1)$ 额外空间;返回数组本身占 $O(k)$。
关键点总结
- 杨辉三角第
k行可直接视为组合数序列。- 相邻组合数递推避免了构造整个三角形,也优于 $O(k^2)$ 的滚动动态规划。
- 乘法必须使用 64 位中间变量,转换只发生在最终系数写入时。
- 先乘后除可保持整数结果;调换顺序会因截断丢失精度。
易错点总结
- 将行号按 1 开始理解:第 0 行应为
[1],结果长度是rowIndex + 1。- 用阶乘分别计算组合数:阶乘更早溢出,并重复做大量计算。
- 使用 32 位变量计算乘积:最终系数合法,中间乘积仍可能溢出。
- 写成
value / (j + 1) * (rowIndex - j):整数除法提前截断,例如C(4,1)推下一项时会算错。
相似题目
| 题目 | 难度 | 考察点 |
|---|---|---|
| 118. 杨辉三角 | 简单 | 要输出全部行,反而不能压维,重点在逐行构造与首尾补 1 |
| 120. 三角形最小路径和 | 中等 | 同样是三角形上的一维滚动,但自底向上推进可省去边界特判 |
| 62. 不同路径 | 中等 | 答案本身就是组合数,可对照递推解法与公式解法的取舍 |
| 64. 最小路径和 | 中等 | 依赖上方与左方两个格子,压成一维时遍历方向必须从左往右 |