方法一:基础解法-左右乘积列表
核心公式:对于任意位置i,除自身以外的乘积 = i 左侧所有元素的乘积 × i 右侧所有元素的乘积。
算法步骤:
1.定义两个数组L和R。
L[i]:i 位置左侧所有元素的乘积;R[i]:i 位置右侧所有元素的乘积。
2.初始化边界:第一个元素左边没有元素,L[0] = 1。最后一个元素右面也没有元素,也初始化一R[n-1] = 1
3.从左到右遍历:填充L数组,L[i] = L[i-1] × nums[i-1]
4.从右到左遍历:填充R数组,R[i] = R[i+1] × nums[i+1]
5.最终结果:answer[i] = L[i] × R[i]
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int len = nums.size();
//创建L和R记录
vector<int>L(len,0),R(len,0); //L和R的长度为len然后初始化都为0
vector<int> answer(len);//长度为len的answer存放最终结果
L[0] = 1;//初始化最开始元素的左边的乘积为1
//计算i位置的左边的乘积
for(int i = 1; i <len;i++){
//从左开始遍历这个数组
L[i] = nums[i-1]*L[i-1];
}
R[len-1] = 1;
for(int i = len-2;i>=0;i--){
R[i] = nums[i+1]*R[i+1];
}
for(int i = 0;i<len;i++){
answer[i] = L[i] * R[i];
}
return answer;
}
};
方法二:最优解法(O(1)额外空间)
思路:先用输出数组answer代替方法一的L数组,先存下每个位置的左乘积,省去L数组的空间。
然后不用开R数组,用一个临时变量R,从后往前遍历数组,动态维护当前位置的右侧乘积,边遍历边更新answer数组。
这样全程只用到了常数个临时变量,临时空间复杂度降到了O1
算法步骤:
- 初始化answer,answer[0]=1;
2.从左到右遍历,填充answer数组为每个位置的左乘积
3.第一R = 1;
4.从右向左遍历 第一步:answer[i] = answer[i] × R
.第二步:R = R × nums[i](更新 R,把当前元素乘进去,给前一个位置的右侧乘积用
cpp
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int len = nums.size();
vector<int>answer(len);
answer[0] = 1;
for(int i = 1;i<len;i++)
{
answer[i] = answer[i-1]*nums[i-1];
}
int R = 1;
for(int i = len-1;i>=0;i--){
answer[i] = answer[i] * R;
R *= nums[i];
}
return answer;
}
};