从递归到数学规律:我是怎么把杨辉三角写对的
🟢 题目速览
LeetCode 118. 杨辉三角(简单)
给定一个非负整数numRows,生成杨辉三角的前numRows行。
规则很简单:
每个数是它左上方和右上方的数的和。
每行第一个和最后一个都是 1。
示例:
输入: 5 输出: [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ]🧠 我的第一反应(差点翻车)
看到这种二维结构,我第一反应是:这不就是个二维 List 嘛,直接套两层循环。
于是我写出了大概这样的逻辑:
外层循环控制行数。
内层循环给每一行塞数。
如果是第一个或最后一个,塞 1。
否则,去上一行拿数相加。
结果一跑,直接给我报了个IndexOutOfBoundsException。
我当时一脸懵:“我不是已经判断了j == 0 || j == i了吗?怎么还会越界?”
🔍 排查过程(关键坑点)
后来我盯着代码看了十分钟,终于发现问题出在这:
我把result.add(row)写在内层循环里了。
也就是说,每算一个数,我就把整行加了一遍。
算第 0 个:加一次 row
算第 1 个:又加一次 row
这就导致result里的行数乱了,等到下一行去result.get(i-1)拿上一行数据时,拿到的根本不是我想的那个。
还有一个隐藏问题:
当i = 0的时候,如果不特殊处理,第一行会是空的,这也直接导致后面全崩。
🚀 正确的姿势:理清索引关系
冷静下来重新理逻辑,其实杨辉三角的规律非常死板,不需要瞎猜:
第 i 行有 i + 1 个数(i 从 0 开始)。
首尾一定是 1。
中间的数 = 上一行[j-1] + 上一行[j]。
只要保证:一行算完了,再丢进结果集里,就不会乱。
✅ 最终代码(可直接交)
class Solution { public List<List<Integer>> generate(int numRows) { List<List<Integer>> result = new ArrayList<>(); for (int i = 0; i < numRows; i++) { List<Integer> row = new ArrayList<>(); for (int j = 0; j <= i; j++) { if (j == 0 || j == i) { row.add(1); } else { int left = result.get(i - 1).get(j - 1); int right = result.get(i - 1).get(j); row.add(left + right); } } // ✅ 关键:一行结束了再 add result.add(row); } return result; } }🔍 执行过程拆解(n = 5)
行号 i | 计算过程 | 当前行 |
|---|---|---|
0 | 只有一个 1 | [1] |
1 | 1 + 1 | [1, 1] |
2 | 1, (1+1), 1 | [1, 2, 1] |
3 | 1, (1+2), (2+1), 1 | [1, 3, 3, 1] |
4 | 1, (1+3), (3+3), (3+1), 1 | [1, 4, 6, 4, 1] |
🎯 我踩过的坑(避坑指南)
别急着往结果里加
❌ 内层循环里
add(row)✅ 外层循环结束再
add(row)
边界一定要死记
第一行必须是
[1]每一行第一个和最后一个一定是
1
索引别写反
result.get(i - 1)才是上一行j - 1和j别搞混
🧩 一句话总结
杨辉三角看似是数学题,其实是数组索引控制题。
只要你记住:一行算完再存,首尾填 1,中间去上一行拿数,这题就稳了。
🎤 面试怎么说(建议背)
“这题我用模拟的方式来做。
用一个二维 List 存储结果,外层循环控制行数。
每一行第一个和最后一个元素固定为 1,中间的元素通过上一行的两个相邻元素相加得到。
注意要把整行构造完成后再加入结果集,避免索引错乱。”
写完这篇我才发现,很多题不是难,而是我们太着急下手写了。
先画图,再写代码,真的能救命。
