Skip to main content

除自身以外数组的乘积

给你一个整数数组 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]

简单做法:双指针遍历

进阶做法:通过分别计算每个元素的前缀乘积和后缀乘积,然后将它们相乘得到结果。

方法思路

  1. 前缀乘积数组:创建一个数组 prefix,其中 prefix[i] 表示 nums 中索引 i 左侧所有元素的乘积(不包含 nums[i])。
  2. 后缀乘积数组:创建一个数组 suffix,其中 suffix[i] 表示 nums 中索引 i 右侧所有元素的乘积(不包含 nums[i])。
  3. 结果数组:遍历每个元素,将其前缀乘积和后缀乘积相乘,得到最终结果。

代码实现

function productExceptSelf(nums) {
const n = nums.length;
const answer = new Array(n).fill(1);

// 计算前缀乘积
let prefix = 1;
for (let i = 0; i < n; i++) {
answer[i] *= prefix;
prefix *= nums[i];
}

// 计算后缀乘积并与前缀乘积相乘
let suffix = 1;
for (let i = n - 1; i >= 0; i--) {
answer[i] *= suffix;
suffix *= nums[i];
}

return answer;
}

代码解释

  1. 初始化结果数组answer 初始化为全 1,用于存储最终结果。
  2. 计算前缀乘积
    • 从左到右遍历 nums,用变量 prefix 记录当前元素左侧所有元素的乘积。
    • 更新 answer[i]prefix,然后将当前元素乘入 prefix
  3. 计算后缀乘积并合并结果
    • 从右到左遍历 nums,用变量 suffix 记录当前元素右侧所有元素的乘积。
    • answer[i] 乘以 suffix,然后将当前元素乘入 suffix

复杂度分析

  • 时间复杂度:O(n),两次线性遍历。
  • 空间复杂度:O(1)(除结果数组外,仅使用常数级额外空间)。

示例分析

输入 nums = [1, 2, 3, 4]

  1. 计算前缀乘积
    • prefix = 1answer[0] = 1
    • prefix = 1*1 = 1answer[1] = 1
    • prefix = 1*2 = 2answer[2] = 2
    • prefix = 2*3 = 6answer[3] = 6
    • 此时 answer = [1, 1, 2, 6]
  2. 计算后缀乘积并合并
    • suffix = 1answer[3] *= 1 → 6
    • suffix = 1*4 = 4answer[2] *= 4 → 8
    • suffix = 4*3 = 12answer[1] *= 12 → 12
    • suffix = 12*2 = 24answer[0] *= 24 → 24
    • 最终 answer = [24, 12, 8, 6]

正确性验证

  • 对于每个元素 nums[i],其结果为左侧元素乘积(前缀)与右侧元素乘积(后缀)的乘积,符合题目要求。
  • 无需除法,且仅使用两次遍历,满足 O(n) 时间复杂度。

这种方法通过预处理前缀和后缀乘积,巧妙地避免了除法运算,高效解决了问题。