剑指Offer:构建乘积数组的高效解法

发布时间:2026/11/2 20:16:55
剑指Offer:构建乘积数组的高效解法 1. 问题背景与核心挑战这道来自《剑指Offer》的经典算法题要求我们实现一个特殊数组的构建给定一个数组A需要构建一个新数组B其中B[i]的值等于数组A中除了A[i]之外所有元素的乘积。题目还特别强调了一个限制条件——不能使用除法运算。这个限制条件直接排除了最直观的解法先计算整个数组的乘积然后对每个元素除以A[i]得到B[i]。这种解法虽然简单但存在两个致命缺陷一是当数组中出现0时会导致除零错误二是题目明确禁止使用除法运算。2. 解题思路分析2.1 暴力解法及其缺陷最直接的思路是对于每个B[i]都遍历整个数组A跳过当前元素A[i]计算其余元素的乘积。这种方法的时间复杂度是O(n²)当数组较大时性能会急剧下降。def constructArr(a): b [1] * len(a) for i in range(len(b)): for j in range(len(a)): if i ! j: b[i] * a[j] return b2.2 优化思路分而治之更高效的解法是将问题分解为两个部分对于每个元素B[i]可以看作是其左边所有元素的乘积乘以其右边所有元素的乘积。这样我们就可以通过两次遍历来完成计算第一次从左到右遍历计算每个元素左边所有元素的乘积存入临时数组第二次从右到左遍历计算每个元素右边所有元素的乘积并与之前的结果相乘得到最终结果这种方法的时间复杂度是O(n)空间复杂度也是O(n)需要存储中间结果。3. 详细实现步骤3.1 初始化工作首先我们需要初始化结果数组B并将其所有元素设为1。同时我们还需要一个临时变量来存储累积的乘积。def constructArr(a): if not a: return [] length len(a) b [1] * length3.2 左遍历计算左下三角乘积从左到右遍历数组计算每个位置左边所有元素的乘积并存入结果数组B中。# 计算左下三角乘积 temp 1 for i in range(1, length): temp * a[i-1] b[i] temp3.3 右遍历计算右上三角乘积从右到左遍历数组计算每个位置右边所有元素的乘积并与之前的结果相乘得到最终结果。# 计算右上三角乘积并相乘 temp 1 for i in range(length-2, -1, -1): temp * a[i1] b[i] * temp return b3.4 完整代码实现将上述步骤组合起来得到完整的解决方案def constructArr(a): if not a: return [] length len(a) b [1] * length # 计算左下三角乘积 temp 1 for i in range(1, length): temp * a[i-1] b[i] temp # 计算右上三角乘积并相乘 temp 1 for i in range(length-2, -1, -1): temp * a[i1] b[i] * temp return b4. 算法复杂度分析4.1 时间复杂度该算法只需要两次遍历数组每次遍历的时间复杂度都是O(n)因此总的时间复杂度是O(n)。4.2 空间复杂度除了结果数组B外我们只使用了常数级别的额外空间temp变量因此空间复杂度是O(1)不考虑结果数组的空间。5. 边界条件与特殊测试用例5.1 空数组输入assert constructArr([]) []5.2 单元素数组assert constructArr([5]) [1]5.3 包含0的数组assert constructArr([1, 0, 3, 4]) [0, 12, 0, 0]5.4 全1数组assert constructArr([1, 1, 1, 1]) [1, 1, 1, 1]6. 实际应用场景这种构建乘积数组的算法在实际开发中有多种应用场景图像处理在计算像素邻域统计量时可能需要排除中心像素的影响数据分析计算某些统计指标时需要排除当前数据点的影响推荐系统计算用户相似度时可能需要排除某些特定项目的影响7. 常见错误与调试技巧7.1 索引越界问题在实现过程中特别要注意数组索引的范围。例如在右遍历时起始索引应该是length-2而不是length-1。7.2 初始值设置临时变量temp的初始值应该设置为1而不是0否则所有乘积结果都会变成0。7.3 边界条件处理需要特别注意空数组和单元素数组的特殊情况避免在这些情况下出现错误。8. 算法优化空间虽然这个算法已经相当高效但仍有一些可能的优化方向空间优化可以尝试将中间结果存储在输入数组中如果允许修改输入数组并行计算对于超大数组可以考虑将左右乘积的计算并行化缓存优化对于频繁调用的场景可以考虑缓存中间结果9. 类似题目扩展掌握这个算法后可以尝试解决以下类似题目LeetCode 238. Product of Array Except Self计算数组所有子数组的乘积计算数组中每个元素左边/右边小于它的元素个数10. 个人实现心得在实际编码实现时我发现以下几点特别值得注意画图辅助理解通过绘制数组元素的乘积关系图可以更直观地理解算法的运作机制分步验证先实现左遍历部分验证结果正确后再实现右遍历部分测试驱动开发先编写测试用例再实现功能代码可以确保各种边界条件都被覆盖这个问题的解法展示了如何通过巧妙的分解将看似复杂的问题简化为可管理的子问题。这种分而治之的思想在算法设计中非常常见掌握这种思维方式对解决其他算法问题也大有裨益。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询