LeetCode 题目 118:杨辉三角

题目描述

给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。在杨辉三角中,每个数是它左上方和右上方的数的和。

杨辉三角解析

在这个详解中,我们将使用 ASCII 图形来说明杨辉三角的构建过程,包括逐行添加新的行的过程。这个图解可以帮助理解每一行是如何基于前一行构建的。

杨辉三角的构建过程

初始状态
  1. 开始时,杨辉三角是空的。
第1行
  1. 添加第一行,只有一个数字 1

    1

第2行
  1. 第二行有两个 1,每个都位于行的边界。

    1
    1 1

第3行
  1. 第三行中间的数字是上一行两个相邻数字之和(1 + 1)。

    1
    1 1
    1 2 1

第4行
  1. 第四行,中间的两个数字分别是上一行相邻两数之和(1+2 和 2+1)。

     1
    1 1
    

    1 2 1
    1 3 3 1

第5行
  1. 第五行,中间三个数字由上行相邻数字之和得到(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 个数字。

解题思路与算法

方法一:逐行构建
解题步骤:
  1. 初始化一个空列表 triangle 作为结果。
  2. 遍历从 0numRows-1 的每一行。
  3. 对于每一行,创建一个长度等于行号加一的新行,首尾元素设为1。
  4. 对于每一行的中间元素,按照杨辉三角的规则,由上一行的相邻两个元素求和得到。
  5. 将构建好的行添加到 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
方法二:一行代码解
解题步骤:
  1. 使用列表推导式和递推公式直接生成杨辉三角的每一行。
  2. 利用 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)]
方法三:动态规划
解题步骤:
  1. 初始化一个空列表 triangle
  2. 从第一行到第 numRows 行,利用动态规划的思想,每一行基于前一行生成。
  3. 同样地,每行的首尾元素为1,其他元素由上一行的两个相邻元素相加得到。
  4. 每生成一行即存入 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. 定义递归函数,如果请求行数为1,返回只包含一行的杨辉三角。
  2. 否则,递归调用自身生成前 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
方法五:迭代改进版
解题步骤:
  1. 初始化一个包含第一行的列表。
  2. 迭代从第二行开始,每一行都通过上一行来计算。
  3. 使用临时列表存储当前行,计算完成后加入最终结果。
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)),但因为使用了列表推导,可能有额外的内存开销。

不同算法的优劣势对比

  • 逐行构建(方法一)直观易理解,适合大多数初学者。
  • 一行代码解(方法二)代码简洁,但可能在理解和调试时较为复杂。
  • 动态规划(方法三)标准且易于理解,展示了动态规划思想的典型应用。
  • 使用递归(方法四)代码简洁,但对于大的行数可能导致调用栈溢出。
  • 迭代改进版(方法五)提供了介于方法一和方法三之间的解决方案,保持了代码的清晰性和执行的高效性。

应用示例

杨辉三角可以用于计算组合数学中的二项式系数,这在概率论、统计学和算法设计中非常有用。例如,它可以用来计算多项式展开的系数,或者在计算概率时快速找到相关的系数。在图形设计中,杨辉三角也被用于计算贝塞尔曲线等复杂图形的点。

相关推荐
Re.不晚1 分钟前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
凤枭香6 分钟前
Python OpenCV 傅里叶变换
开发语言·图像处理·python·opencv
测试杂货铺14 分钟前
外包干了2年,快要废了。。
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展
艾派森18 分钟前
大数据分析案例-基于随机森林算法的智能手机价格预测模型
人工智能·python·随机森林·机器学习·数据挖掘
小码的头发丝、44 分钟前
Django中ListView 和 DetailView类的区别
数据库·python·django
为什么这亚子1 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
1 小时前
开源竞争-数据驱动成长-11/05-大专生的思考
人工智能·笔记·学习·算法·机器学习
~yY…s<#>1 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
Chef_Chen2 小时前
从0开始机器学习--Day17--神经网络反向传播作业
python·神经网络·机器学习
千澜空2 小时前
celery在django项目中实现并发任务和定时任务
python·django·celery·定时任务·异步任务