问题描述:
给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。
在杨辉三角中,每个数是它左上方和右上方的数的和。
示例:
输入: 3 输出: [1,3,3,1]
进阶:
你可以优化你的算法到 O(k) 空间复杂度吗?
基本思路:
一开始我的想法就是利用杨辉三角形和排列组合公式相结合。
为了存储我的结果我确实需要O(k)的空间。
但是这样超出了long long的范围。(算阶乘的时候signed integer overflow了,其实完全没有必要算到这么大)
于是考虑时间换空间的做法。
(附signed integer overflow的代码)
class Solution {
public:
long long C(int m, int n) { // m > n
long long up = 1;
long long down = 1;
for (int i = 0; i < n; ++i) {
up *= (m - i);
down *= (i + 1);
}
return up / down;
}
vector<int> getRow(int rowIndex) {
vector<int> res;
for (int i = 0; i <= rowIndex; ++i) {
res.push_back(C(rowIndex, i));
}
return res;
}
};
注意到可以使用滚动数组的思想。
即每一层遍历的时候还是使用同样的数组,但是要经过一定的技巧使我们要用到的元素不会被提前覆盖掉。
观察得如果我们从后往前覆盖数组,之前必须的元素就不会被覆盖掉。
和以上算法的对比就在于我们不得不一层一层地计算得到。
AC代码:
class Solution {
public:
vector<int> getRow(int rowIndex) {
// rowIndex + 1个0
vector<int> row(rowIndex + 1, 0);
row[0] = 1;
for (int i = 1; i <= rowIndex; ++i) {
for (int j = i; j >= 1; --j)
row[j] = row[j] + row[j - 1];
}
return row;
}
};
其他经验:
- 使用滚动数组的思想重复利用空间。
- 注意滚动数组中覆盖的顺序,不要让我们需要使用到的元素被提前覆盖了。
- 做稍微大一点数字的乘法的时候注意signed integer overflow的错误。