> 技术文档 > LeetCode - 238. 除自身以外数组的乘积

LeetCode - 238. 除自身以外数组的乘积

目录

题目

核心思想

算法步骤

图解示例

时间和空间复杂度

读者可能出现的错误写法

正确的写法


题目

238. 除自身以外数组的乘积 - 力扣(LeetCode)

核心思想

使用双指针,将每个位置的结果分解为两部分的乘积:

  • 该位置左侧所有元素的乘积
  • 该位置右侧所有元素的乘积

算法步骤

创建结果数组:初始化为全1,因为乘法的单位元是1

 vector 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]:

  1. 初始化:result = [1,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 productExceptSelf(vector& nums) { vector result(nums.size(),1); int left = 1; for(int i = 0; i0;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 productExceptSelf(vector& nums) { vector result(nums.size(),1); int left = 1; for(int i = 0; i=0; i--) { result[i] = result[i] * right; right = right*nums[i]; //更新right } return result; }};