☰
LeetCode数组乘积问题:前缀积与后缀积解法详解
2026/10/31 9:08:37 网站建设 项目流程

1. 问题背景与核心挑战

今天要讨论的是LeetCode热题HOT100中的一道经典数组操作题目——"除自身以外数组的乘积"。这道题在面试中出现频率极高,考察的是对数组遍历和空间复杂度的掌控能力。题目要求我们给定一个整数数组nums,返回一个数组answer,其中answer[i]等于nums中除nums[i]之外其余各元素的乘积。

这个问题的难点在于:

  • 不能使用除法运算(题目明确限制)
  • 时间复杂度必须控制在O(n)
  • 空间复杂度除输出数组外需为O(1)(进阶要求)

我第一次遇到这个问题时,直观想到的暴力解法是对于每个元素都遍历整个数组计算乘积,但这样时间复杂度会达到O(n²),显然不符合要求。后来经过反复推敲,发现可以通过前缀积和后缀积的巧妙组合来优化。

2. 算法思路解析

2.1 前缀积与后缀积的概念

解决这个问题的关键在于理解前缀积(Prefix Product)和后缀积(Suffix Product):

  • 前缀积表示数组从开始到当前元素前一个位置所有元素的乘积
  • 后缀积表示从当前元素后一个位置到数组末尾所有元素的乘积

以数组[1,2,3,4]为例:

  • 对于元素2(索引1),其前缀积是1,后缀积是3×4=12
  • 对于元素3(索引2),其前缀积是1×2=2,后缀积是4

2.2 空间优化策略

最直观的解法是分别计算并存储每个元素的前缀积和后缀积,然后将两者相乘得到最终结果。但这样需要额外的两个数组,空间复杂度为O(n)。

进阶解法通过复用输出数组来实现O(1)空间复杂度(不考虑输出数组):

  1. 先用输出数组存储前缀积
  2. 再用一个变量动态计算后缀积,同时更新输出数组

3. 具体实现步骤

3.1 基础实现(空间复杂度O(n))

def productExceptSelf(nums): n = len(nums) prefix = [1] * n suffix = [1] * n answer = [1] * n # 计算前缀积 for i in range(1, n): prefix[i] = prefix[i-1] * nums[i-1] # 计算后缀积 for i in range(n-2, -1, -1): suffix[i] = suffix[i+1] * nums[i+1] # 合并结果 for i in range(n): answer[i] = prefix[i] * suffix[i] return answer

3.2 优化实现(空间复杂度O(1))

def productExceptSelf(nums): n = len(nums) answer = [1] * n # 先用answer存储前缀积 for i in range(1, n): answer[i] = answer[i-1] * nums[i-1] # 动态计算后缀积并更新answer suffix = 1 for i in range(n-1, -1, -1): answer[i] *= suffix suffix *= nums[i] return answer

4. 复杂度分析与边界情况

4.1 时间复杂度

两种实现方式都只需要两次遍历数组,时间复杂度均为O(n)。

4.2 空间复杂度

  • 基础实现:使用了prefix和suffix两个额外数组,空间复杂度O(n)
  • 优化实现:仅使用常数空间存储suffix,空间复杂度O(1)(不考虑输出数组)

4.3 边界情况处理

  • 空数组:直接返回空数组
  • 单元素数组:返回[1](因为没有任何其他元素)
  • 包含0的数组:需要特别注意,但题目保证乘积不会溢出32位整数范围

5. 常见错误与调试技巧

5.1 典型错误

  1. 忘记初始化前缀/后缀数组的第一个/最后一个元素
  2. 在优化实现中,后缀积计算时没有正确更新suffix变量
  3. 索引越界(特别是在处理边界元素时)

5.2 调试建议

  • 对于小数组(如[1,2,3,4])手动计算每一步的结果
  • 打印中间变量(prefix、suffix)检查是否正确
  • 特别注意循环的起始和终止条件

6. 算法扩展与变种

6.1 允许使用除法的情况

如果题目允许使用除法,可以先计算所有元素的乘积,然后对于每个元素用总乘积除以当前元素。但需要注意:

  • 数组中可能有0(需要特殊处理)
  • 题目通常明确禁止使用除法

6.2 多维数组扩展

这个问题可以扩展到二维矩阵,计算除当前元素外所有行和列的乘积。思路类似,但需要分别计算行前缀积和列前缀积。

7. 实际应用场景

这种算法思想在以下场景中有实际应用:

  • 图像处理中的邻域计算
  • 统计学中的滑动窗口计算
  • 金融分析中的累积收益率计算

8. 个人实现心得

在实际编码时,我发现以下几点特别重要:

  1. 先写出基础解法确保逻辑正确,再考虑优化
  2. 画图辅助理解前缀和后缀的关系
  3. 对于优化解法,特别注意更新变量的顺序

重要提示:在面试中,建议先解释基础解法,再提出优化思路,最后实现优化解法。这能展示你的思考过程。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询