每日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(函数式编程),平衡可读性和性能

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

相关推荐
报错小能手9 分钟前
C++笔记(面向对象)静态联编和动态联编
开发语言·c++·算法
WBluuue16 分钟前
AtCoder Beginner Contest 430(ABCDEF)
c++·算法
小肖爱笑不爱笑18 分钟前
2025/11/5 IO流(字节流、字符流、字节缓冲流、字符缓冲流) 计算机存储规则(ASCII、GBK、Unicode)
java·开发语言·算法
熬了夜的程序员34 分钟前
【LeetCode】99. 恢复二叉搜索树
算法·leetcode·职场和发展
Kent_J_Truman39 分钟前
LeetCode Hot100 自用
算法·leetcode·职场和发展
还是码字踏实39 分钟前
算法题种类与解题思路全面指南:基于LeetCode Hot 100与牛客Top 101
算法·leetcode
社恐的下水道蟑螂1 小时前
从字符串到像素:深度解析 HTML/CSS/JS 的页面渲染全过程
javascript·css·html
程序定小飞1 小时前
基于springboot的web的音乐网站开发与设计
java·前端·数据库·vue.js·spring boot·后端·spring
舒一笑1 小时前
从手写周报到智能生成:PandaCoder如何让你的工作汇报效率提升10倍
后端·程序员·intellij idea
无名之辈J1 小时前
支付常犯错误
后端