题目描述
给定一个整数数组 nums,返回一个数组 answer,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。要求:
- 不能使用除法
- 时间复杂度为 O(n)O(n)
- 空间复杂度为 O(1)O(1)(输出数组不计入空间复杂度)
解题思路
核心思想:通过两次遍历分别计算每个元素左侧和右侧的乘积,最终将两侧乘积相乘得到结果。
- 左侧乘积计算。
- 左侧乘积计算(从左向右遍历):
- 初始化 `answer:
- 初始化
answer = 1(首元素左侧无元素) - 对于每个位置
i,answer[i] = nums × nums × ... × nums[i-1] - 递推公式:
answer[i] = answer[i-1] × nums[i-1]
- 右侧乘积计算(从右向左遍历):
- 用变量
right_product动态维护右侧乘积(初始为1) - 对于每个位置
i,将answer[i]乘上右侧乘积right_product - 更新
right_product *= nums[i](为下一个元素准备)
- 用变量
关键洞察
- 将结果分解为左侧乘积 × 右侧乘积
- 复用输出数组存储中间结果,避免额外空间
- 右侧乘积通过动态更新变量高效计算
复杂度分析
| 指标 | 值 | 说明 |
|---|---|---|
| 时间复杂度 | O(n)O(n) | 两次独立遍历数组 |
| 空间复杂度 | O(1)O(1) | 仅使用常数变量(输出数组不计入) |
代码实现
- JavaScript
var productExceptSelf = function(nums) {
const n = function(nums) {
const n = nums.length;
const answer = new Array(n).fill(1);
// 计算左侧乘积
for (let i = 1; i < n; i++) {
answer[i] = answer[i-1] * nums[i-1];
}
// 计算右侧乘积并合并结果
let rightProduct = 1;
for (let i = n-1; i >= 0; i--) {
answer[i] *= rightProduct;
rightProduct *= nums[i];
}
return answer;
};
- python
def productExceptSelf(nums):
n = len(nums)
answer = [1] * n
# 计算左侧乘积
for i in range(1, n):
answer[i] = answer[i-1] * nums[i-1]
# 计算右侧乘积并合并结果
right_product = 1
for i in range(n-1, -1, -1):
answer[i] *= right_product
right_product *= nums[i]
return answer
- rust
impl Solution {
pub fn product_except_self(nums: Vec) -> Vec {
let n = nums.len();
let mut answer = vec![1; n];
// 计算左侧乘积
for i in 1..n {
answer[i] = answer[i-1] * nums[i-1];
}
// 计算右侧乘积并合并结果
let mut right_product = 1;
for i in (0..n).rev() {
answer[i] *= right_product;
right_product *= nums[i];
}
answer
}
}
实际应用场景
- 信号处理:计算滤波器中每个采样点除自身外的加权乘积
- 数据压缩:在矩阵运算中避免零值干扰的权重计算
- 金融分析:计算资产组合中各资产对总收益的贡献度(排除自身影响)
- 图像处理:像素邻域计算中排除中心像素的影响