链接:杨辉三角
描述:

给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。比如给定5,则生成以下数组。

1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1

思路:

既然是讲递归,那么就先寻找规律。根据杨辉三角的定义,很容易的知道第n行和第n+1行元素之间的关系——假设低n行的数据为f(n),f(n,x)为第n行的x个元素,则f(n+1,x) = f(n,x-1) + f(n,x)。可以很容易的想到通过递归得到任意行的数据,之后只要遍历n遍即可得到想要的杨辉三角了。代码如下:

class Solution {public:
// 生成杨辉三角
vector<vector<int>> generate(int numRows) {
vector<vector<int>> ret;

for (size_t i = 0; i < numRows; i++)
{
ret.push_back(getLine(i+1));
}
return ret;
}

// 得到杨辉三角中指定行的数据
vector<int> getLine(int row)
{
vector<int> ret;
for (size_t i = 0; i < row; i++)
{
if (i == 0 || i == row - 1)
{
ret.push_back(1);
continue;
}

vector<int> vLast = getLine(row - 1);
int nValue = vLast[i - 1] + vLast[i];
ret.push_back(nValue);
}

return ret;
}};

问题:

虽然很容易的解决了问题,但是这里存在一个弊端,就是运行超时。因为当为了获取f(n+1)的数据时,它会先获取f(n),但是f(n)又依赖于f(n-1),这样当为了 得到f(5)的数据,f(4)被调用2次,f(3)被调用4次,f(2)被调用8次,造成时间和空间上成指数的开销。为了解决这个问题,非递归实现是一个更好的选择。

非递归实现

vector<vector<int>> generate(int numRows) {
vector<vector<int>> ret;

for (size_t i = 0; i < numRows; i++)
{
vector<int> row;
for (size_t k = 0; k < i + 1; k++)
{
if (k == 0 || k == i)
{
row.push_back(1);
continue;
}
row.push_back(ret[i - 1][k - 1] + ret[i - 1][k]);
}

ret.push_back(row);
}
return ret;
}

这个解法大比递归不管是时间还是空间复杂度都降低了很多,但其实还可以做进一步的优化。仔细观察,杨辉三角的每一行都是对称的,此时只需要获取f(n)中的0~n/2+1的数据,然后将他们复制到后面即可。优化的代码这里就不再给出了(因为我懒_)