题目描述
给定一个非负整数 numRows
,生成杨辉三角的前 numRows
行。在杨辉三角中,每个数是它左上方和右上方的数的和。
杨辉三角解析
在这个详解中,我们将使用 ASCII 图形来说明杨辉三角的构建过程,包括逐行添加新的行的过程。这个图解可以帮助理解每一行是如何基于前一行构建的。
杨辉三角的构建过程
初始状态
- 开始时,杨辉三角是空的。
第1行
-
添加第一行,只有一个数字
1
。1
第2行
-
第二行有两个
1
,每个都位于行的边界。1
1 1
第3行
-
第三行中间的数字是上一行两个相邻数字之和(1 + 1)。
1
1 1
1 2 1
第4行
-
第四行,中间的两个数字分别是上一行相邻两数之和(1+2 和 2+1)。
1 1 1
1 2 1
1 3 3 1
第5行
-
第五行,中间三个数字由上行相邻数字之和得到(1+3、3+3 和 3+1)。
1 1 1 1 2 1 1 3 3 1
1 4 6 4 1
总结过程
- 杨辉三角的每一行都从
1
开始和结束。 - 除了第一个和最后一个数字外,每个数字都是它正上方两个数字的和。
- 第
n
行(从1
开始计数)有n
个数字。
解题思路与算法
方法一:逐行构建
解题步骤:
- 初始化一个空列表
triangle
作为结果。 - 遍历从
0
到numRows-1
的每一行。 - 对于每一行,创建一个长度等于行号加一的新行,首尾元素设为1。
- 对于每一行的中间元素,按照杨辉三角的规则,由上一行的相邻两个元素求和得到。
- 将构建好的行添加到
triangle
中。
Python 代码示例
python
def generate(numRows):
"""生成杨辉三角的前numRows行"""
triangle = []
for row_num in range(numRows):
row = [None for _ in range(row_num + 1)]
row[0], row[-1] = 1, 1 # 第一个和最后一个元素始终为1
for j in range(1, len(row) - 1):
row[j] = triangle[row_num - 1][j - 1] + triangle[row_num - 1][j]
triangle.append(row)
return triangle
方法二:一行代码解
解题步骤:
- 使用列表推导式和递推公式直接生成杨辉三角的每一行。
- 利用 Python 的生成器语法简化代码实现。
Python 代码示例
python
def generate(numRows):
"""一行代码生成杨辉三角"""
return [[1 if j == 0 or j == i else triangle[i-1][j-1] + triangle[i-1][j] for j in range(i+1)] for i in range(numRows)]
方法三:动态规划
解题步骤:
- 初始化一个空列表
triangle
。 - 从第一行到第
numRows
行,利用动态规划的思想,每一行基于前一行生成。 - 同样地,每行的首尾元素为1,其他元素由上一行的两个相邻元素相加得到。
- 每生成一行即存入
triangle
。
Python 代码示例
python
def generate(numRows):
triangle = []
for row_num in range(numRows):
row = [1] * (row_num + 1) # 每行元素初始化为1
for j in range(1, row_num):
row[j] = triangle[-1][j - 1] + triangle[-1][j]
triangle.append(row)
return triangle
方法四:使用递归
解题步骤:
- 定义递归函数,如果请求行数为1,返回只包含一行的杨辉三角。
- 否则,递归调用自身生成前
numRows - 1
行,然后基于最后一行计算新的一行,并添加到结果中。
Python 代码示例
python
def generate(numRows):
if numRows == 1:
return [[1]]
else:
result = generate(numRows - 1)
last_row = result[-1]
new_row = [1]
for i in range(1, len(last_row)):
new_row.append(last_row[i - 1] + last_row[i])
new_row.append(1)
result.append(new_row)
return result
方法五:迭代改进版
解题步骤:
- 初始化一个包含第一行的列表。
- 迭代从第二行开始,每一行都通过上一行来计算。
- 使用临时列表存储当前行,计算完成后加入最终结果。
Python 代码示例
python
def generate(numRows):
triangle = [[1]]
for row_number in range(1, numRows):
prev_row = triangle[-1]
current_row = [1]
for j in range(1, row_number):
current_row.append(prev_row[j-1] + prev_row[j])
current_row.append(1)
triangle.append(current_row)
return triangle
算法分析
- 时间复杂度 :
- 所有方法的时间复杂度基本为 (O(n^2)),其中 (n) 是行数。每行的计算成本大约与行号成正比。
- 空间复杂度 :
- 方法一、三、四和五:(O(n^2)),需要存储整个三角形。
- 方法二:同样是 (O(n^2)),但因为使用了列表推导,可能有额外的内存开销。
不同算法的优劣势对比
- 逐行构建(方法一)直观易理解,适合大多数初学者。
- 一行代码解(方法二)代码简洁,但可能在理解和调试时较为复杂。
- 动态规划(方法三)标准且易于理解,展示了动态规划思想的典型应用。
- 使用递归(方法四)代码简洁,但对于大的行数可能导致调用栈溢出。
- 迭代改进版(方法五)提供了介于方法一和方法三之间的解决方案,保持了代码的清晰性和执行的高效性。
应用示例
杨辉三角可以用于计算组合数学中的二项式系数,这在概率论、统计学和算法设计中非常有用。例如,它可以用来计算多项式展开的系数,或者在计算概率时快速找到相关的系数。在图形设计中,杨辉三角也被用于计算贝塞尔曲线等复杂图形的点。