LeetCode - 238. 除自身以外数组的乘积
目录
题目
核心思想
算法步骤
图解示例
时间和空间复杂度
读者可能出现的错误写法
正确的写法
题目
238. 除自身以外数组的乘积 - 力扣(LeetCode)
核心思想
使用双指针,将每个位置的结果分解为两部分的乘积:
- 该位置左侧所有元素的乘积
- 该位置右侧所有元素的乘积
算法步骤
创建结果数组:初始化为全1,因为乘法的单位元是1
vector<int> result(nums.size(), 1);
第一次遍历(从左到右):计算每个位置左侧所有元素的乘积
- 维护一个变量left,表示当前位置左侧所有元素的乘积,初始值为1
对于每个位置i:
- 将left的值乘到result[i]上
- 更新left,乘上当前元素nums[i],为下一个位置做准备
int left = 1;for(int i = 0; i < nums.size(); i++) {result[i] *= left; // 当前位置乘以左侧乘积left *= nums[i]; // 更新左侧乘积}
第二次遍历(从右到左):计算每个位置右侧所有元素的乘积,并与之前结果相乘
- 维护一个变量right,表示当前位置右侧所有元素的乘积,初始值为1
- 对于每个位置i(从右往左):
- 将right的值乘到result[i]上
- 更新right,乘上当前元素nums[i],为下一个位置做准备
图解示例
对于数组 [1,2,3,4]:
- 初始化:result = [1,1,1,1]
- 第一次遍历(左→右):
- i=0: left=1, result[0]=1*1=1, left=1*1=1
- i=1: left=1, result[1]=1*1=1, left=1*2=2
- i=2: left=2, result[2]=1*2=2, left=2*3=6
- i=3: left=6, result[3]=1*6=6, left=6*4=24
此时 result = [1,1,2,6]
第二次遍历(右→左):
- i=3: right=1, result[3]=6*1=6, right=1*4=4
- i=2: right=4, result[2]=2*4=8, right=4*3=12
- i=1: right=12, result[1]=1*12=12, right=12*2=24
- i=0: right=24, result[0]=1*24=24, right=24*1=24
最终 result = [24,12,8,6]
时间和空间复杂度
- 时间复杂度:O(n),只需要两次遍历数组
- 空间复杂度:O(1),除了结果数组外,只使用了常数额外空间
int right = 1;for(int i = nums.size()-1; i >= 0; i--) {result[i] *= right; // 当前位置乘以右侧乘积right *= nums[i]; // 更新右侧乘积}
读者可能出现的错误写法
class Solution {
public:vector<int> productExceptSelf(vector<int>& nums) {vector<int> result(nums.size(),1);int left = 1;for(int i = 0; i< nums.size();i++){left = nums[i];result = result * left;}int right = 1;for(int i = n-1;i>0;i++){right = nums[i];result = result * right;}return result;}
};
left = nums[i]; - 这里是错误的赋值。应该是将当前结果乘以左侧乘积,然后更新左侧乘积。
result = result * left; - 这是错误的语法。不能直接用向量乘以整数,需要对向量的每个元素进行操作。
for(int i = n-1;i>0;i++) - 这里有三个问题:
- 使用了未定义的变量 n(应该是 nums.size())
- 循环条件应该是 i >= 0,否则会漏掉索引0
- 递增运算符应该是 i--,否则会导致无限循环
右侧遍历的逻辑也有问题,不应该直接赋值 right = nums[i]
正确的写法
class Solution {
public:vector<int> productExceptSelf(vector<int>& nums) {vector<int> result(nums.size(),1);int left = 1;for(int i = 0; i< nums.size();i++){result[i] = result[i] * left;left = left*nums[i]; //更新left}int right = 1;for(int i = nums.size()-1; i>=0; i--){result[i] = result[i] * right;right = right*nums[i]; //更新right}return result;}
};