方法一:递推
杨辉三角具有以下性质:
- 每行数字左右对称,由 1开始逐渐变大再变小,并最终回到 1。
- 第 n 行(从 0 开始编号)的数字有 n+1 项,前 n 行共有个数。
- 第 n 行的第 m 个数(从 0 开始编号)可表示为可以被表示为组合数C(n,m),记作,即为从n个不同元素中取 m 个元素的组合数。我们可以用公式来表示它
- 每个数字等于上一行的左右两个数字之和,可用此性质写出整个杨辉三角。即第 nn 行的第 ii 个数等于第n−1 行的第 i-1个数和第 ii 个数之和。这也是组合数的性质之一,即
- 的展开式(二项式展开)中的各项系数依次对应杨辉三角的第 n 行中的每一项。
依据性质 4,我们可以一行一行地计算杨辉三角。每当我们计算出第 i行的值,我们就可以在线性时间复杂度内计算出第 i+1 行的值。
class Solution {
public List<Integer> getRow(int rowIndex) {
List<List<Integer>> C = new ArrayList<List<Integer>>();
for (int i = 0; i <= rowIndex; ++i) {
List<Integer> row = new ArrayList<Integer>();
for (int j = 0; j <= i; ++j) {
if (j == 0 || j == i) {
row.add(1);
} else {
row.add(C.get(i - 1).get(j - 1) + C.get(i - 1).get(j));
}
}
C.add(row);
}
return C.get(rowIndex);
}
}
优化
注意到对第 i+1行的计算仅用到了第 i行的数据,因此可以使用滚动数组的思想优化空间复杂度。
class Solution {
public List<Integer> getRow(int rowIndex) {
List<Integer> pre = new ArrayList<Integer>();
for (int i = 0; i <= rowIndex; ++i) {
List<Integer> cur = new ArrayList<Integer>();
for (int j = 0; j <= i; ++j) {
if (j == 0 || j == i) {
cur.add(1);
} else {
cur.add(pre.get(j - 1) + pre.get(j));
}
}
pre = cur;
}
return pre;
}
}
进一步优化
能否只用一个数组呢?
只用一个数组的优化,思想类似于01背包问题中的优化,需要用逆向思维,每一行的数值都从右往左求出,这样在下一行中求相同列值时,既可以直接读出上一行用数组保留的值,计算后,也可以在原数组的基础上直接覆盖元素,而不影响下一个值(即左边的元素)的计算。
class Solution {
public List<Integer> getRow(int rowIndex) {
List<Integer> row = new ArrayList<Integer>();
row.add(1);
for (int i = 1; i <= rowIndex; ++i) {
row.add(0);
for (int j = i; j > 0; --j) {
row.set(j, row.get(j) + row.get(j - 1));
}
}
return row;
}
}
方法二:线性递推
由
得:
而C(0, n) = 1,则利用上式可以在线性时间内计算出第n行的所有组合数
class Solution {
public List<Integer> getRow(int rowIndex) {
List<Integer> row = new ArrayList<Integer>();
row.add(1);
for (int i = 1; i <= rowIndex; ++i) {
row.add((int) ((long) row.get(i - 1) * (rowIndex - i + 1) / i));
}
return row;
}
}。