返回

除自身外的数组乘积,化繁为简的解法

前端

在算法领域,我们经常会遇到一些看似复杂但又暗藏简便之道的难题。今天,我们将探讨一个经典问题:除自身外的数组乘积

问题定义

给定一个长度为 n 的整数数组 nums(其中 n > 1),求输出数组 output,其中 output[i] 等于 nums 中除 nums[i] 之外的其余各元素的乘积。

例如,对于数组 [1, 2, 3, 4]output[12, 6, 4, 3]

朴素解法

最直接的解法是逐个计算每个元素的乘积。时间复杂度为 O(n^2),空间复杂度为 O(n)

def product_except_self_brute(nums):
  output = [1] * len(nums)
  for i in range(len(nums)):
    for j in range(len(nums)):
      if i != j:
        output[i] *= nums[j]
  return output

利用前缀和后缀乘积

一种更有效的方法是利用前缀乘积和后缀乘积。

  • 前缀乘积:对于元素 nums[i],其前缀乘积为 [nums[0], nums[1], ..., nums[i-1]] 的乘积。
  • 后缀乘积:对于元素 nums[i],其后缀乘积为 [nums[i+1], nums[i+2], ..., nums[n-1]] 的乘积。

利用这些乘积,我们可以通过以下公式计算 output[i]

output[i] = (前缀乘积[i-1] * 后缀乘积[i+1]) / nums[i]

算法步骤:

  1. 初始化前缀乘积和后缀乘积数组。
  2. 遍历数组,计算每个元素的前缀乘积。
  3. 从后往前遍历数组,计算每个元素的后缀乘积。
  4. 根据公式计算 output[i]

代码实现:

def product_except_self_prefix_suffix(nums):
  prefix = [1] * len(nums)
  suffix = [1] * len(nums)
  output = [1] * len(nums)
  
  # 计算前缀乘积
  for i in range(1, len(nums)):
    prefix[i] = prefix[i-1] * nums[i-1]
  
  # 计算后缀乘积
  for i in range(len(nums)-2, -1, -1):
    suffix[i] = suffix[i+1] * nums[i+1]
  
  # 计算输出
  for i in range(len(nums)):
    output[i] = prefix[i-1] * suffix[i+1]
  
  return output

优化空间复杂度

上述算法的空间复杂度为 O(n),我们可以进一步优化为 O(1)

算法步骤:

  1. 初始化变量 prefix 为 1,表示前缀乘积。
  2. 遍历数组,计算每个元素 nums[i] 的前缀乘积,并将其存储在 prefix 中。
  3. 初始化变量 suffix 为 1,表示后缀乘积。
  4. 从后往前遍历数组,计算每个元素 nums[i] 的后缀乘积,并将其存储在 suffix 中。
  5. 根据公式计算 output[i]

代码实现:

def product_except_self_optimized(nums):
  output = [1] * len(nums)
  prefix = 1
  
  # 计算前缀乘积
  for i in range(len(nums)):
    output[i] = prefix
    prefix *= nums[i]
  
  # 计算后缀乘积
  suffix = 1
  for i in range(len(nums)-1, -1, -1):
    output[i] *= suffix
    suffix *= nums[i]
  
  return output

总结

我们介绍了三种计算除自身外的数组乘积的方法:朴素解法、利用前缀和后缀乘积的方法,以及优化空间复杂度的优化方法。通过不断优化算法,我们实现了算法效率和空间消耗的平衡。