🔗 除自身以外数组的乘积
题目来源:238. 除自身以外数组的乘积 – 力扣(LeetCode)
📌 题目描述
给你一个整数数组 nums
,返回数组 answer
,其中 answer[i]
等于 nums
中除 nums[i]
之外其余各元素的乘积。
- 要求:
- 不能使用除法。
- 在
O(n)
时间复杂度内完成。 - 题目保证结果在 32 位整数范围内。
✅ 示例解析
示例 1:
- 输入:
nums = [1,2,3,4]
- 输出:
[24,12,8,6]
- 解释:
answer[0] = 2*3*4 = 24
answer[1] = 1*3*4 = 12
answer[2] = 1*2*4 = 8
answer[3] = 1*2*3 = 6
示例 2:
- 输入:
nums = [-1,1,0,-3,3]
- 输出:
[0,0,9,0,0]
- 解释:
- 由于数组中存在
0
,除nums[2]
外的所有answer[i]
都包含0
,故为0
。 answer[2] = (-1)*1*(-3)*3 = 9
- 由于数组中存在
⚠️ 提示
2 <= nums.length <= 10⁵
-30 <= nums[i] <= 30
- 结果保证在 32 位整数范围内
💡 解法:前缀乘积 + 后缀乘积(两次遍历)—— O(n) 时间,O(1) 额外空间
class Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] result = new int[n];
result[0] = 1;
for (int i = 1; i < n; i++) {
result[i] = result[i - 1] * nums[i - 1];
}
int right = 1;
for (int i = n - 1; i >= 0; i--) {
result[i] = result[i] * right;
right = right * nums[i];
}
return result;
}
}
📊 复杂度分析
- 时间复杂度:O(n)
- 第一次遍历计算前缀乘积:O(n)
- 第二次遍历计算后缀乘积并更新结果:O(n)
- 总体为线性时间。
- 空间复杂度:O(1)(不计返回数组)
result
数组为返回值,不计入额外空间。- 仅使用常数变量
right
,满足题目对空间的要求。
🧩 解题思路
- 核心思想:分解为前缀与后缀乘积
对于任意位置i
,answer[i] = (nums[0] * ... * nums[i-1]) * (nums[i+1] * ... * nums[n-1])
即:左边所有元素的乘积 × 右边所有元素的乘积 - 两步走策略:
- 步骤 1:计算前缀乘积
使用result
数组先存储每个位置i
的左侧元素乘积。result[0] = 1
(左边无元素)result[i] = result[i-1] * nums[i-1]
(递推)
- 步骤 2:计算后缀乘积并合并
从右向左遍历,用变量right
动态维护当前位置i
的右侧元素乘积。- 初始
right = 1
(最右元素右边无元素) result[i] *= right
:将右侧乘积乘到结果中right *= nums[i]
:更新right
,为下一轮(i-1)准备
- 初始
- 步骤 1:计算前缀乘积
- 举例说明:
对nums = [1,2,3,4]
:- 步骤 1 后:
result = [1, 1, 2, 6]
result[1] = 1 * nums[0] = 1
result[2] = 1 * nums[1] = 2
result[3] = 2 * nums[2] = 6
- 步骤 2 过程:
- i=3:
result[3] = 6 * 1 = 6
,right = 1 * 4 = 4
- i=2:
result[2] = 2 * 4 = 8
,right = 4 * 3 = 12
- i=1:
result[1] = 1 * 12 = 12
,right = 12 * 2 = 24
- i=0:
result[0] = 1 * 24 = 24
,right = 24 * 1 = 24
- i=3:
- 最终
result = [24,12,8,6]
✅
- 步骤 1 后:
- 处理特殊情况(含 0):
- 该方法天然支持
0
:- 若
nums[i] = 0
,则result[i]
只包含左侧乘积,右侧乘积由right
传递 - 如示例 2,
right
在遇到0
前为3
,在i=2
时result[2] = 2 * 3 = 6
? - 实际过程会正确计算:
right
会因0
而变为0
,后续result[i]
也变为0
,但i=2
时right
还未乘0
,因此能正确得到9
。
- 若
- 该方法天然支持