LeetCode 119:杨辉三角 II
题目描述
给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。
在杨辉三角中,每个数是它左上方和右上方的数的和。
【示例】
输入: 3
输出: [1,3,3,1]
进阶:
你可以优化你的算法到 O(k) 空间复杂度吗?
解题
数学法
与杨辉三角I思路一致,直接计算,唯一的问题是行数过高时会超int范围,所以中间结果要先转换到更高的数据类型上。
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<int> vect(1,1);
for (int i=1; i<=rowIndex; ++i)
vect.emplace_back(static_cast<long long>(vect[i-1])*(rowIndex-i+1)/i); //这里前两项相乘会超出int范围
return vect;
}
};
杨辉三角的特性
与杨辉三角I思路一样,将杨辉三角左对齐发现:
[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]
a
j
i
=
a
j
i
−
1
+
a
j
−
1
i
−
1
,
j
≥
1
,
i
≥
1
a_{j}^{i}=a_{j}^{i-1}+a_{j-1}^{i-1},j\ge 1,i\ge1
aji=aji−1+aj−1i−1,j≥1,i≥1
上一时刻数组总长比这一时刻小1,因此可以在上一时刻数组后面加个0,保证对齐,且可以直接从最右向左更新。
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<int> vect(1,1);
for (int i=1; i<=rowIndex; ++i){
vect.emplace_back(0);
for (int j=i; j>=1; --j)
vect[j] = vect[j]+vect[j-1];
}
return vect;
}
};
上下两段代码的基本思路是一样的,不同点在于更新的方式。下面这种方法在每次循环中构造当前行所对应的数组(多余的1除外)。比如输入为3,它的循环过程如下:
首先构造[1, 1, 1, 1]
第一次循环结果[1,2,1,1],最左边三个恰好是输入为2的结果[1,2,1]
第二次循环结果[1,3,3,1],得到目标结果。
算法要计算的实际上是除两端1之外的值,因此只有输入大于等于2时才会进入循环体。
假如输入为4,最开始构造[1,1,1,1,1]
第一次循环结果[1,2,1,1,1],最左边三个恰好是输入为2的结果[1,2,1]
第二次循环结果[1,3,3,1,1],最左边四个恰好是输入为3的结果[1,3,3,1]
最三次循环结果[1,4,6,4,1],得到目标解
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<int> vect(rowIndex+1,1);
for (int i=2; i<=rowIndex; ++i){
for (int j=i-1; j>=1; --j)
vect[j] = vect[j]+vect[j-1];
}
return vect;
}
};
迭代实现
我们也可以使用迭代方式实现上述算法。
class Solution {
private:
void getRow(int rowIndex, vector<int>&out){
if (rowIndex<0) return;
if (rowIndex==0) {
out[0]=1;
return;
}
getRow(rowIndex-1, out);
for (int i=rowIndex; i>0; --i)
out[i]+=out[i-1];
}
public:
vector<int> getRow(int rowIndex) {
vector<int> out(rowIndex+1, 0);
getRow(rowIndex, out);
return out;
}
};