「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」。
题目描述🌍
给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
示例 1:
输入: rowIndex = 3
输出: [1,3,3,1]
示例 2:
输入: rowIndex = 0
输出: [1]
示例 3:
输入: rowIndex = 1
输出: [1,1]
提示:
0 <= rowIndex <= 33
进阶:你可以优化你的算法到 空间复杂度吗?
暴力求解💦
解题思路
参考上一篇求整个「杨辉三角」的思路,我们可以先通过 公式逐行求解杨辉三角前 rowIndex + 1 行,然后返回非负索引 rowIndex 对应的那一行即可。
代码
Java
class Solution {
public List<Integer> getRow(int rowIndex) {
List<List<Integer>> triangle = new ArrayList<>();
for (int i = 0; i <= rowIndex; i++) {
List<Integer> row = new ArrayList<>();
for (int j = 0; j <= i; j++) {
if (j == 0 || j == i) {
row.add(1);
} else {
row.add(triangle.get(i - 1).get(j - 1) + triangle.get(i - 1).get(j));
}
}
triangle.add(row);
}
return triangle.get(rowIndex);
}
}
C++
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<vector<int>> ret(rowIndex + 1);
for (int i = 0; i < rowIndex + 1; ++i) {
ret[i].resize(i + 1);
ret[i][0] = ret[i][i] = 1;
for (int j = 1; j < i; ++j) {
ret[i][j] = ret[i - 1][j - 1] + ret[i - 1][j];
}
}
return ret[rowIndex];
}
};
时间复杂度:
空间复杂度:
滚动数组「优化暴力解法」🌈
解题思路
滚动数组的作用在于优化空间。
是否觉得方法一过于多余?计算第 rowIndex 行竟然要保存前 rowIndex - 1 行的数据,无形中提高了空间复杂度!这里我们通过「滚动数组」的思想优化下空间。
由 公式可知,计算第 n 行只需第 n - 1 行的数据,所以只需不断更新上一行数组即可。
代码
Java
class Solution {
public List<Integer> getRow(int rowIndex) {
List<Integer> preLine = new ArrayList<>();
for (int i = 0; i <= rowIndex; i++) {
List<Integer> curLine = new ArrayList<>();
for (int j = 0; j <= i; j++) {
if (j == 0 || j == i) {
curLine.add(1);
} else {
curLine.add(preLine.get(j - 1) + preLine.get(j));
}
}
preLine = curLine;
}
return preLine;
}
}
C++
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<int> cur_line, pre_line;
for (int i = 0; i < rowIndex + 1; ++i) {
cur_line.resize(i + 1);
cur_line[0] = cur_line[i] = 1;
for (int j = 1; j < i; ++j) {
cur_line[j] = pre_line[j - 1] + pre_line[j];
}
pre_line = cur_line;
}
return cur_line;
}
};
时间复杂度:
空间复杂度:
补位逆向递推「优化滚动数组」👑
解题思路
由方法二 preLine = curLine 代码可以看出在计算过程中,当前行在计算过程中保存着上一行的数据,所以我们通过当前行自身来获取 与 元素,然后对当前行元素逆序修改(从后往前覆盖才不会丢失上一行所留下的数据)。
注:因为每一行都比上一行多一个元素,所以递推过程中要补一个末位元素。
代码
Java
class Solution {
public List<Integer> getRow(int rowIndex) {
List<Integer> row = new ArrayList<>();
row.add(1);
for (int i = 0; i < rowIndex; i++) {
// 首先添加末位元素
row.add(1);
// 逆序修改元素
for (int j = i; j > 0; j--) {
row.set(j, row.get(j) + row.get(j - 1));
}
}
return row;
}
}
C++
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<int> row(rowIndex + 1);
row[0] = 1;
for (int i = 0; i < rowIndex; ++i) {
row[i + 1] = 1;
for (int j = i; j > 0; --j) {
row[j] = row[j] + row[j - 1];
}
}
return row;
}
};
时间复杂度:
空间复杂度:
前后递推求解🚀
前三种方法都用到了「动态规划」的思想,但其实杨辉三角的某一行可以直接求解。
解题思路
由公式 与 可以推出前后元素间的递推公式: 。
⭐注:求解元素过程中可能会溢出 int 数据类型的范围 : 所以计算过程中先转为 long 类型再将最终值转为 int 类型。
代码
Java
class Solution {
public List<Integer> getRow(int rowIndex) {
List<Integer> row = new ArrayList<>();
row.add(1);
for (int i = 1; i <= rowIndex; i++) {
row.add((int) ((long) row.get(i - 1) * (rowIndex - i + 1) / i));
}
return row;
}
}
C++
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<long> row_long(rowIndex + 1);
row_long[0] = 1;
for (int i = 1; i < rowIndex + 1; ++i) {
row_long[i] = row_long[i - 1] * (rowIndex - i + 1) / i;
}
// casting vector<long> to vector<int>, only method..
vector<int> row(row_long.begin(), row_long.end());
return row;
}
};
时间复杂度:
空间复杂度:
最后🌅
该篇文章为 「LeetCode」 系列的 No.13 篇,在这个系列文章中:
- 尽量给出多种解题思路
- 提供题解的多语言代码实现
- 记录该题涉及的知识点
👨💻争取做到 LeetCode 每日 1 题,所有的题解/代码均收录于 「LeetCode」 仓库,欢迎随时加入我们的刷题小分队!