每日LeetCode : 杨辉三角

杨辉三角相信大家都不陌生,这是一道经典的编程题目,它的解法多种多样,在组合数学、概率统计和多项式展开中也有重要应用。

今天,我就带大家从最常见的开始,逐渐对它的解法进行优化迭代。

题目描述

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

示例:

ini 复制代码
输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]

解法1:基础迭代法(双重循环)

核心思想:逐行构建杨辉三角,每行的第一个和最后一个元素为1,中间元素为上一行相邻两个元素之和,可以将原本的等边三角形视作直角三角形解答。

javascript 复制代码
function generate(numRows) {
    if (numRows === 0) return [];
    
    const triangle = [[1]];
    
    for (let i = 1; i < numRows; i++) {
        const prevRow = triangle[i - 1];
        const currentRow = [1]; // 每行第一个元素总是1
        
        // 计算中间元素
        for (let j = 1; j < i; j++) {
            currentRow[j] = prevRow[j - 1] + prevRow[j];
        }
        
        currentRow.push(1); // 每行最后一个元素总是1
        triangle.push(currentRow);
    }
    
    return triangle;
}

解题思路

  1. 边界处理 :当 numRows 为0时直接返回空数组
  2. 初始化 :创建第一行 [1]
  3. 逐行构建
    • 每行的第一个元素总是1
    • 中间元素 = 上一行左上方元素 + 上一行右上方元素
    • 每行的最后一个元素总是1
  4. 添加到结果:将每行加入结果数组

时间复杂度 :O(n²)
空间复杂度:O(n²)(存储整个三角形)

注意点

  1. 索引越界 :访问 prevRow[j] 时,要确保 j < prevRow.length
  2. 边界处理 :忘记处理 numRows = 0 的情况
  3. 行首行尾:每行的第一个和最后一个元素必须设为1
  4. 初始行:第一行需要单独初始化

解法2:函数式编程(数组映射)

核心思想 :利用数组的 mapreduce 方法,以更声明式的方式构建杨辉三角。

javascript 复制代码
function generate(numRows) {
    const triangle = [];
    
    for (let i = 0; i < numRows; i++) {
        // 创建当前行数组
        const row = Array(i + 1).fill(1);
        
        // 计算中间元素(跳过首尾)
        for (let j = 1; j < i; j++) {
            row[j] = triangle[i - 1][j - 1] + triangle[i - 1][j];
        }
        
        triangle.push(row);
    }
    
    return triangle;
}

优化点

  1. 统一初始化 :使用 Array(i + 1).fill(1) 一次性创建并填充数组
  2. 代码简洁:减少了对首尾元素的特殊处理
  3. 可读性:更清晰地表达"创建长度为i+1且全为1的数组"的意图

易错点

  1. 填充值覆盖 :中间元素计算时会覆盖初始填充的1,确保循环范围正确(j < i
  2. 空数组处理 :当 numRows=0 时返回空数组
  3. 行索引 :访问 triangle[i-1] 时确保 i > 0

解法3:动态规划优化(单数组迭代)

核心思想:只保留上一行数据,减少空间复杂度,同时使用对称性优化计算。

javascript 复制代码
function generate(numRows) {
    if (numRows === 0) return [];
    if (numRows === 1) return [[1]];
    
    const triangle = [[1], [1, 1]];
    
    for (let i = 2; i < numRows; i++) {
        const prevRow = triangle[i - 1];
        const row = [1];
        const mid = Math.ceil(i / 2);
        
        // 计算左半部分
        for (let j = 1; j < mid; j++) {
            row[j] = prevRow[j - 1] + prevRow[j];
        }
        
        // 利用对称性复制右半部分
        for (let j = mid; j <= i; j++) {
            row[j] = row[i - j];
        }
        
        triangle.push(row);
    }
    
    return triangle;
}

优化点

  1. 空间优化:只需访问上一行而非所有历史行
  2. 对称性利用:杨辉三角左右对称,只需计算一半元素
  3. 边界处理:单独处理前两行,简化主循环逻辑

易错点

  1. 对称索引row[j] = row[i - j] 确保索引计算正确
  2. 中间点Math.ceil(i/2) 处理奇偶行差异
  3. 特殊行处理:确保前两行正确初始化

解法4:数学公式法(组合数)

核心思想:利用杨辉三角与组合数的关系(第n行第k个元素 = C(n,k))

javascript 复制代码
function generate(numRows) {
    const factorial = n => {
        if (n <= 1) return 1;
        return n * factorial(n - 1);
    };
    
    const triangle = [];
    
    for (let n = 0; n < numRows; n++) {
        const row = [];
        for (let k = 0; k <= n; k++) {
            // C(n,k) = n! / (k! * (n-k)!)
            row.push(factorial(n) / (factorial(k) * factorial(n - k)));
        }
        triangle.push(row);
    }
    
    return triangle;
}

特点

  1. 数学本质:直接体现杨辉三角的数学原理
  2. 精确计算:避免累加误差
  3. 概念清晰:明确展示杨辉三角与二项式系数的关系

缺点

  1. 计算效率:阶乘计算时间复杂度高(O(n³))
  2. 数值限制:大数阶乘可能导致数值溢出
  3. 递归深度:阶乘递归可能造成栈溢出

总结与选择建议

  • 推荐解法:解法1(基础迭代法),简单直观,适用于大多数场景
  • 性能敏感:解法3(动态规划优化),空间效率更高
  • 数学探索:解法4(组合数法),适合理解数学本质但不适合实际应用
  • 代码简洁:解法2(函数式编程),平衡可读性和性能

杨辉三角不仅是经典的编程题目,更在组合数学、概率统计和多项式展开中有重要应用。理解其生成算法有助于培养动态规划思维和发现数学模式的能力。

相关推荐
程序员爱钓鱼6 分钟前
Go语言实战案例-简易计算器(加减乘除)
后端
DoraBigHead9 分钟前
小哆啦解题记——两数失踪事件
前端·算法·面试
不太可爱的大白9 分钟前
Mysql分片:一致性哈希算法
数据库·mysql·算法·哈希算法
学不会就看11 分钟前
Django--01基本请求与响应流程
后端·python·django
Tiandaren4 小时前
Selenium 4 教程:自动化 WebDriver 管理与 Cookie 提取 || 用于解决chromedriver版本不匹配问题
selenium·测试工具·算法·自动化
岁忧5 小时前
(LeetCode 面试经典 150 题 ) 11. 盛最多水的容器 (贪心+双指针)
java·c++·算法·leetcode·面试·go
chao_7895 小时前
二分查找篇——搜索旋转排序数组【LeetCode】两次二分查找
开发语言·数据结构·python·算法·leetcode
Nejosi_念旧6 小时前
解读 Go 中的 constraints包
后端·golang·go
一斤代码6 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
风无雨6 小时前
GO 启动 简单服务
开发语言·后端·golang