「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。
题目
给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex **行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
示例 1:
输入: rowIndex = 3
输出: [1,3,3,1]
示例 2:
输入: rowIndex = 0
输出: [1]
示例 3:
输入: rowIndex = 1
输出: [1,1]
提示: 0 <= rowIndex <= 33
进阶: 你可以优化你的算法到 O(rowIndex) 空间复杂度吗?
解题思路
方法一:DP
外层循环从上往下一层层求,复用一维数组 res(滚动数组),计算每个位置上的元素,只取决于上一行的值。
内层遍历的递推式为res[j] = res[j] + res[j-1],要保证等号右边的两个,是上一行的“旧值”。
如果内层遍历是从左往右,会出现res[j-1]是本行的上一轮迭代求出的新值,不是上一行的旧值。
所以,内层遍历的方向取从右往左。这样保证了计算新值时,等号右边都是旧值。
var getRow = function(rowIndex) {
const res = new Array(rowIndex + 1);
res[0] = 1;
for (let i = 1; i < rowIndex + 1; i++) {
res[0] = res[i] = 1;
for (let j = i - 1; j >= 1; j--) {
res[j] = res[j] + res[j - 1];
}
}
return res;
};
方法二:递归(超时了)
定义递归函数:返回出第 i 行,第 j 列的元素值。
递归的公式是 cal(i,j) = cal(i-1, j-1) + cal(i-1, j)
递归的结束条件是:当 j == 0 || i == j,元素值为1,返回1,它其实就是 dp 的 base case。
var getRow = function(rowIndex) {
const res = new Array(rowIndex + 1);
for (let j = 0; j < rowIndex + 1; j++) {
res[j] = cal(rowIndex, j);
}
return res
};
var cal = function(i, j) {
if (j == 0 || i == j) {
return 1;
}
return cal(i-1, j-1) + cal(i-1, j);
}
当遇到 30 这个case 就超时了
方法三:记忆划递归
用一个二维数组memo,存计算过的子问题的结果,当遇到相同的递归子问题时,直接返回缓存值,避免落入重复的递归。
基于上面代码轻轻一改就有了如下
var getRow = function(rowIndex) {
const memo = new Array(rowIndex + 1);
for (let i = 0; i < memo.length; i++) {
memo[i] = new Array(i + 1);
}
for (let j = 0; j < rowIndex + 1; j++) {
memo[rowIndex][j] = cal(rowIndex, j, memo);
}
return memo[rowIndex]
};
var cal = function(i, j, memo) {
if (j == 0 || i == j) {
return 1;
}
if (memo[i][j] > 0) {
return memo[i][j];
}
memo[i][j] = cal(i-1, j-1, memo) + cal(i-1, j, memo);
return memo[i][j]
}
结束语
这里是小葵🌻,只要把心朝着太阳的地方,就会有温暖~
让我们一起来攻克算法难关吧!!