Hello,大家好。夜深人静宿自宽,不羡鸳鸯不羡仙!我是猿码。
前几日与同事聊起算法,他说算法很难,从来没有接触过。而在我看来,算法已经不在那么神秘,她真正妖娆的地方是无穷的规律与精简。我们中国有句古话叫“大道至简,大悟无言”,前半句用来形容算法真的很贴切,但是后半句可以用来形容领悟了算法背后规律的心情。
恩,话不多说了,我们开始探索算法背后编程乐趣的真正细节吧!
🔍 题目:给一个数字n,
,请构建一个杨辉三角。
📕 题目介绍
杨辉三角相关定义:
- 杨辉三角是由
行数量不同的数列组成,由于规律排列后形似三角形,且为古代数学家杨辉或贾宪所发现,因此叫杨辉或贾宪三角
- 规律排列后,该几何具有对称性,且三角形左右两边的数字都是 1
- 第
行第
列元素为
行 第
列与第
列元素之和
- 当
时,设每行的数字数量为
,数列为
,则有
,
- 当
,
时,则有
难度:容易 (Easy)
题目来源:力扣(LeetCode)
💡 题目分析
具体公式,已经在定义中列举出来了,可以结合 Gif 图来分析其原理。
这道题由于每行的数字列数呈递增趋势,且行数编号与列数相等,其中行数从 1 开始。因此,在选择数据结构上,我们优先考虑可变数组 ArrayList。
这道题唯一需要注意的地方是:对于三角中固定值与被计算出来的值的处理方式。固定值,分布在行的两端,这两个值可以直接在循环中手动添加到子集合当中即可。被计算出来的值,在不使用公式的前提下,是需要去 中去取,然后进行计算得出。因此我们需要在原有的循环内部,再创建一个从 2 开始,
结束的内循环。
🖊 代码实现
public List<List<Integer>> generate(int numRows) {
// 父集合
List<List<Integer>> ans = new ArrayList<>();
// 子集合
List<Integer> row = new ArrayList<>();
// 手动添加第 1 行
row.add(1); ans.add(row);
for (int i = 1; i < numRows; i++) {
// 子集合
row = new ArrayList<>(i + 1);
// 添加固定值 1
row.add(1);
// 当 i > 1 时,第 2 个数字与第 numRows - 2
// 个数字与当前行数对应,可以直接添加,无需计算
if(i > 1) row.add(i);
if(i > 3) {
// 当 i > 3 时再去遍历父集合计算当前集合需要的元素
for(int j = 2; j <= i - 2; j++) {
row.add(ans.get(i - 1).get(j - 1) + ans.get(i - 1).get(j));
}
}
// 第 numRows - 2 个数字与行数对应无需计算
if(i > 2) row.add(i);
row.add(1);
ans.add(row);
}
return ans;
}
时间复杂度:,
为三角的总行数,去掉常数和低阶项
空间复杂度:,这里包括返回值的占用空间
📕总结
学习点:
- 如何处理固定元素与被计算出来的元素
- 如何选择一个合适的数据结构处理数据