当前位置: 首页 > news >正文

算法238. 除自身以外数组的乘积

🧩 题目描述

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。
题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。
请 不要使用除法,且在 O(n) 时间复杂度内完成此题。
示例 1:
输入: nums = [1,2,3,4]
输出: [24,12,8,6]
示例 2:
输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

进阶:你可以在 O(1) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组 不被视为 额外空间。)


✅ 解法:前后缀分解(Prefix and Suffix Product)

🔑 核心思想

将每个位置 i 的答案拆分为两部分:

  • i 左边所有元素的乘积 → pre[i]
  • i 右边所有元素的乘积 → suf[i]

则:
answer[i]=pre[i]×suf[i]\text{answer}[i] = \text{pre}[i] \times \text{suf}[i] answer[i]=pre[i]×suf[i]

这称为「前后缀分解」技巧,是处理“除自身外乘积”类问题的标准方法。


🧱 算法步骤

  1. 构造前缀乘积数组 pre

    • pre[i] 表示 nums[0] × nums[1] × ... × nums[i-1]
    • 即:从左到右,不包含 nums[i] 的乘积
    • 初始值:pre[0] = 1(空乘积定义为 1)
  2. 构造后缀乘积数组 suf

    • suf[i] 表示 nums[i+1] × nums[i+2] × ... × nums[n-1]
    • 即:从右到左,不包含 nums[i] 的乘积
    • 初始值:suf[n-1] = 1
  3. 合并结果

    • answer[i] = pre[i] * suf[i]

💻 代码实现

class Solution:def productExceptSelf(self, nums: List[int]) -> List[int]:n = len(nums)# Step 1: 构造前缀乘积 pre[i] = nums[0] * ... * nums[i-1]pre = [1]  # pre[0] = 1(左边没有元素)for i in range(1, n):pre.append(pre[i-1] * nums[i-1])# Step 2: 构造后缀乘积 suf[i] = nums[i+1] * ... * nums[n-1]suf = [1] * n  # 初始化 suf 数组# 从右往左计算for i in range(n-2, -1, -1):suf[i] = suf[i+1] * nums[i+1]# Step 3: 合并前后缀return [p * s for p, s in zip(pre, suf)]

📊 示例演示

nums = [1, 2, 3, 4]
inums[i]pre[i](左边乘积)suf[i](右边乘积)answer[i] = pre[i] × suf[i]
0112×3×4 = 241 × 24 = 24
1213×4 = 121 × 12 = 12
231×2 = 242 × 4 = 8
341×2×3 = 616 × 1 = 6

✅ 输出:[24, 12, 8, 6]


📌 关键细节说明

1. 为什么 pre[0] = 1

  • 表示 nums[0] 左边没有元素,空乘积定义为 1(乘法单位元)
  • 类似地,suf[n-1] = 1

2. 递推公式

  • pre[i] = pre[i-1] * nums[i-1]
  • suf[i] = suf[i+1] * nums[i+1]

3. 为什么不能用除法?

  • 题目明确禁止
  • 而且如果 nums 中有 0,除法会出错或需要特殊处理

⚡ 进阶优化:空间复杂度 O(1)(不计输出数组)

可以将 pre 直接作为答案数组,再用一个变量从右往左累乘后缀:

class Solution:def productExceptSelf(self, nums: List[int]) -> List[int]:n = len(nums)answer = [1] * n# Step 1: answer[i] 先存 pre[i]for i in range(1, n):answer[i] = answer[i-1] * nums[i-1]# Step 2: 用 right 表示后缀乘积,从右往左更新 answerright = 1for i in range(n-1, -1, -1):answer[i] *= rightright *= nums[i]return answer
  • ✅ 时间复杂度:O(n)
  • ✅ 空间复杂度:O(1)(不计输出数组)

🧠 方法本质:分治思想

把“整体乘积除以自身”转化为:

  • 左边乘积 × 右边乘积

避免了对每个位置重新计算,实现高效递推。


📚 相似题目推荐

题目链接思路关联
135. 分发糖果左右两次遍历类似前后缀思想
2104. 子数组范围和前后缀 + 单调栈范围最值乘积
1991. 找到数组的中间位置前缀和基础前缀思想

✅ 总结

技巧说明
前后缀分解将复杂问题拆解为左右两部分独立计算
空乘积为 1保证递推边界正确
避免除法更通用,适用于含 0 的情况
可空间优化用输出数组或单变量替代额外空间

📌 一句话记住:
左积 × 右积 = 除自身外的总积
—— 掌握前后缀分解,轻松应对“除自身外乘积”类问题!


http://www.dtcms.com/a/317560.html

相关文章:

  • 完整的登陆学生管理系统(配置数据库)
  • VSCode git提交记录中文commit显示乱码
  • 碰撞问题的分析
  • OpenAI开源大模型gpt-oss系列深度解析:从120B生产级到20B桌面级应用指南
  • C++实现线程池(3)缓存线程池
  • get请求中文字符参数乱码问题
  • 互联网一线大厂Java面试八股文整理(1000题附答案)
  • MATLAB深度学习之数据集-数据库构建方法详解
  • Leetcode——209. 长度最小的子数组
  • Redis中间件(二):Redis协议与异步方式
  • 用docker的方式快速搭建一个Hive的调测环境
  • Java 字节码文件(.class)的组成详解
  • 具有柔性关节的机械臂matlab仿真
  • 在Word和WPS文字中如何输入汉字的偏旁部首
  • 【计算机网络 | 第4篇】分组交换
  • Linux seLinux
  • 网络工程师--华为命令专题
  • 安卓雷电模拟器安装frida调试
  • 《Day2-PyTorch Tensor 从入门到实践:核心操作与避坑指南》
  • jmm 指令重排 缓存可见性 Volatile 内存屏障
  • 数据中心白牌服务器市场规模与发展趋势分析报告-路亿市场策略
  • 丝杆升降机的螺母磨损到什么程度需要更换?有无预警或检测方法?
  • Orange的运维学习日记--31.Linux防火墙深度详解
  • LVS-DR模式高性能负载均衡实战
  • PLC学习之路-定时器-(三)
  • Fabric.js从入门学习到实现labelImg矩形多边形标注工具【上】
  • 论文学习19:Multi-view Aggregation Network for Dichotomous Image Segmentation
  • STM32江科大学习笔记,全功能按键非阻塞式实现,按键点击,双击,长按
  • 思途AOP学习笔记 0806
  • 网安学习no.22