题目描述
给你一个整数数组 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]
思路
productExceptSelf 函数的目的是对于给定的数组 nums,返回一个新数组 ans,其中 ans[i] 等于 nums 中除了 nums[i] 以外的所有元素的乘积。
- 构建左乘积数组 (
left):- 初始化
left[0] = 1,因为对于第一个元素,没有左边的元素。 - 对于每个
i从1到nums.length - 1,计算left[i] = left[i - 1] * nums[i - 1]。 - 这样,
left[i]存储了nums数组中第i个元素左边所有元素的乘积。
- 初始化
- 构建右乘积数组 (
right):- 初始化
right[num.length - 1] = 1,因为对于最后一个元素,没有右边的元素。 - 对于每个
i从nums.length - 2到 0,计算right[i] = right[i + 1] * nums[i + 1]。 - 这样,
right[i]存储了nums数组中第i个元素右边所有元素的乘积。
- 初始化
优化
我们可以直接使用1个遍历来存储右边元素的乘积,并对应乘以left[i],可以减少一次对数组的遍历和right数组的空间开销
计算右乘积并同时构建结果数组 (ans):
- 初始化一个临时变量
temp = 1,用于存储右边所有元素的乘积。 - 从数组的末尾开始遍历,对于每个i从 nums.length - 1到0:
ans[i] = left[i] * temp,即当前位置的结果等于左乘积乘以右乘积。- 更新
temp为temp * nums[i],以便在下一次迭代中使用
复杂度分析
- 时间复杂度:
O(N)- 遍历数组两次(一次构建左乘积,一次计算右乘积并构建结果数组),总时间复杂度为线性级别。
- 空间复杂度:
O(1)(不计输出数组)- 只使用了固定数量的额外变量(如
left数组和temp变量)。如果计入输出数组ans,则空间复杂度为 O(N)。
- 只使用了固定数量的额外变量(如
code
/**
* @param {number[]} nums
* @return {number[]}
*/
var productExceptSelf = function(nums) {
let left = [1];
for(let i = 1; i < nums.length; i++){
left[i] = left[i - 1] * nums[i - 1];
}
let temp = 1, ans = [];
for(let i = nums.length - 1; i >= 0; i--){
ans[i] = temp * left[i];
temp *= nums[i];
}
return ans;
};
// 示例使用
const nums = [1, 2, 3, 4];
console.log(productExceptSelf(nums)); // 输出: [24, 12, 8, 6]