LeetCode 238 - 除自身以外数组的乘积(Product of Array Except Self)
问题描述
给你一个整数数组 nums,返回数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
题目数据 保证 数组 nums 之中任意元素的全部前缀元素和后缀元素的乘积都在 32 位整数范围内。
请 不要使用除法,且在 O(n) 时间复杂度内完成此题。
示例
示例 1:
1 | 输入: nums = [1,2,3,4] |
示例 2:
1 | 输入: nums = [-1,1,0,-3,3] |
约束条件
2 ≤ nums.length ≤ 10⁵-30 ≤ nums[i] ≤ 30- 保证 数组
nums之中任意元素的全部前缀元素和后缀元素的乘积都在 32 位整数范围内
解题思路
对于位置 i 的结果,我们需要计算所有除了 nums[i] 以外的元素乘积。可以将这个乘积分解为两部分:
核心思想:对于位置 i,结果等于 左侧所有元素的乘积 × 右侧所有元素的乘积
1 | 数组: [1, 2, 3, 4] |
根据这个思路,我们可以有多种实现方法。
方法一:暴力解法
实现思路
对于每个位置 i,遍历整个数组计算除了 nums[i] 以外所有元素的乘积。
代码实现
1 | func productExceptSelfBruteForce(nums []int) []int { |
复杂度分析
- 时间复杂度:$O(n^2)$ - 对于每个位置都要遍历整个数组
- 空间复杂度:$O(1)$ - 除了结果数组外,只使用常量额外空间
方法二:前缀和后缀乘积数组
实现思路
- 左乘积数组:
left[i]表示nums[i]左侧所有元素的乘积 - 右乘积数组:
right[i]表示nums[i]右侧所有元素的乘积 - 结果:
result[i] = left[i] × right[i]
详细步骤
以 nums = [1, 2, 3, 4] 为例:
1 | 原数组: [1, 2, 3, 4] |
代码实现
1 | func productExceptSelfTwoArrays(nums []int) []int { |
复杂度分析
- 时间复杂度:$O(n)$ - 三次遍历数组
- 空间复杂度:$O(n)$ - 需要额外的 left 和 right 数组
方法三:空间优化解法(推荐)
实现思路
优化方法二,使用结果数组来存储左乘积,然后用一个变量来维护右乘积,从右向左更新结果。
详细步骤
- 第一遍:结果数组存储每个位置的左乘积
- 第二遍:从右往左遍历,用变量
right维护右乘积,同时更新结果
执行过程演示
以 nums = [1, 2, 3, 4] 为例:
1 | 初始化: nums = [1, 2, 3, 4], result = [0, 0, 0, 0] |
代码实现
1 | func productExceptSelf(nums []int) []int { |
复杂度分析
- 时间复杂度:$O(n)$ - 两次遍历数组
- 空间复杂度:$O(1)$ - 除了结果数组外,只使用常量额外空间
方法四:处理零值的特殊解法
实现思路
考虑到数组中可能包含零值,我们可以:
- 统计零的个数
- 计算所有非零元素的乘积
- 根据零的个数决定结果
代码实现
1 | func productExceptSelfWithZeros(nums []int) []int { |
注意:这个方法违反了题目"不要使用除法"的要求,仅作为思路扩展。
方法比较
| 方面 | 方法一:暴力 | 方法二:两数组 | 方法三:空间优化 | 方法四:特殊处理 |
|---|---|---|---|---|
| 时间复杂度 | $O(n^2)$ | $O(n)$ | $O(n)$ | $O(n)$ |
| 空间复杂度 | $O(1)$ | $O(n)$ | $O(1)$ | $O(1)$ |
| 可读性 | ★★★★☆ | ★★★★★ | ★★★★☆ | ★★★☆☆ |
| 效率 | ★☆☆☆☆ | ★★★★☆ | ★★★★★ | ★★★★☆ |
| 推荐度 | ★☆☆☆☆ | ★★★☆☆ | ★★★★★ | ★★☆☆☆ |
| 适用场景 | 学习理解 | 面试演示思路 | 最优解法 | 违反题目要求 |
关键收获
核心算法概念
- 前缀积和后缀积:将复杂问题分解为左右两部分的乘积
- 空间优化:通过重复利用数组空间来减少额外内存使用
- 双指针思想:一次从左到右,一次从右到左的遍历模式
常见陷阱
- 边界处理:注意数组首尾元素的特殊处理
- 初始值设置:乘积运算的初始值应该是 1,不是 0
- 理解题意:题目要求不使用除法,要避免
product / nums[i]的思路
相关问题
- LeetCode 152: 乘积最大子数组
- LeetCode 628: 三个数的最大乘积
- LeetCode 724: 寻找数组的中心索引
这道题是一个经典的前缀积应用,掌握了这个思路对解决类似的数组乘积问题都很有帮助。
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.
Comments
