力扣打卡每日一题————除自身外所有元素的乘积

一、问题概述

给定一个整数数组 nums,返回一个数组 answer,其中 answer[i] 等于 nums 中除 nums[i] 之外所有元素的乘积。

  • 要求:不能使用除法,且时间复杂度为 O (n)、空间复杂度为 O (1)(返回数组不计入额外空间)。
  • 示例:输入 [1,2,3,4] → 输出 [24,12,8,6](24=2×3×4,12=1×3×4,8=1×2×4,6=1×2×3)。

二、代码核心思路

要计算 "除自身外所有元素的乘积",可以把这个乘积拆成两部分:

  • 左乘积:当前元素左边所有元素的乘积(比如 nums 2=3 的左乘积是 1×2)。
  • 右乘积:当前元素右边所有元素的乘积(比如 nums 2=3 的右乘积是 4)。
  • 最终结果 = 左乘积 × 右乘积。

代码分两步实现:

  1. 先遍历数组,计算每个元素的右乘积 并存储到 answer 数组中;
  2. 再反向遍历数组,计算每个元素的左乘积,并与已存储的右乘积相乘,得到最终结果。

代码逐段解释

第一步:计算右乘积(从后往前遍历)

cpp 复制代码
vector<int> answer(nums.size(),1); // 初始化结果数组,所有元素为1
int nums_add = 1; // 临时变量,存储累积的右乘积
for(int i=nums.size()-1;i>0;i--)
{
    nums_add *= nums[i]; // 累积右乘积(从最后一个元素开始)
    answer[i-1] = nums_add; // 把当前累积的右乘积存入前一个位置
}

关键

  • 初始化 answer 为全 1 数组,因为 "没有元素相乘" 的默认乘积是 1(乘法单位元)。
  • 从数组末尾向前遍历(i 从 n-1 到 1),nums_add 不断乘以当前元素 nums[i],得到的是 nums[i]nums[n-1] 的乘积(即 nums[i-1] 的右乘积)。
  • 示例(nums=1,2,3,4):
    • i=3(nums 3=4):nums_add=1×4=4 → answer 2=4(nums 2=3 的右乘积是 4)。
    • i=2(nums 2=3):nums_add=4×3=12 → answer 1=12(nums 1=2 的右乘积是 12)。
    • i=1(nums 1=2):nums_add=12×2=24 → answer 0=24(nums 0=1 的右乘积是 24)。
    • 第一步结束后,answer = 24,12,4,1

第二步:计算左乘积并合并结果(从前往后遍历)

cpp 复制代码
nums_add = 1; // 重置临时变量,存储累积的左乘积
for(int i=1;i<nums.size();i++)
{
    nums_add *= nums[i-1]; // 累积左乘积(从第一个元素开始)
    answer[i] *= nums_add; // 左乘积 × 已存储的右乘积 = 最终结果
}
return answer;

关键解释

  • 重置 nums_add 为 1,开始累积左乘积(从 nums 0 开始)。
  • 从 i=1 开始遍历,nums_add 不断乘以 nums[i-1],得到的是 nums[0]nums[i-1] 的乘积(即 nums[i] 的左乘积)。
  • 把左乘积与第一步存储的右乘积相乘,得到最终的 "除自身外所有元素的乘积"。
  • 示例(接第一步 answer=24,12,4,1):
    • i=1:nums_add=1×1=1 → answer 1=12×1=12(nums 1=2 的左乘积 1,右乘积 12)。
    • i=2:nums_add=1×2=2 → answer 2=4×2=8(nums 2=3 的左乘积 2,右乘积 4)。
    • i=3:nums_add=2×3=6 → answer 3=1×6=6(nums 3=4 的左乘积 6,右乘积 1)。
    • 第二步结束后,answer = 24,12,8,6(正确结果)。

三、完整执行过程

以输入 nums = [1,2,3,4] 为例:

步骤 变量 / 数组状态 说明
初始化 answer = 1,1,1,1,nums_add=1
第一步 i=3 nums_add=4,answer=1,1,4,1 nums3=4 → answer2=4
第一步 i=2 nums_add=12,answer=1,12,4,1 nums2=3 → answer1=12
第一步 i=1 nums_add=24,answer=24,12,4,1 nums1=2 → answer0=24
第二步重置 nums_add=1
第二步 i=1 nums_add=1,answer=24,12,4,1 nums0=1 → answer1=12×1
第二步 i=2 nums_add=2,answer=24,12,8,1 nums1=2 → answer2=4×2
第二步 i=3 nums_add=6,answer=24,12,8,6 nums2=3 → answer3=1×6
返回结果 answer = 24,12,8,6 最终结果

四、注意事项

  1. 初始化细节answer 数组必须初始化为全 1,因为乘法的 "空乘积" 是 1(比如数组第一个元素的左乘积、最后一个元素的右乘积都是 1)。
  2. 遍历边界
    • 第一步遍历到 i>0(即 i 从 n-1 到 1),避免越界(answer i-1 最小到 answer 0);
    • 第二步遍历从 i=1 开始,因为第一个元素的左乘积是 1,第一步已经算出其右乘积,无需再处理。
  3. 空间复杂度 :仅使用了一个临时变量 nums_add,返回数组不计入额外空间,满足 O (1) 要求。
  4. 无除法限制:全程用乘法累积,符合不能用除法的要求。

五、总结

  1. 核心思想:将 "除自身外乘积" 拆分为左乘积 × 右乘积,分两次遍历分别计算,避免重复运算。
  2. 关键细节:初始化全 1 数组、控制遍历边界、复用结果数组存储中间值,最大化节省空间。
相关推荐
江畔柳前堤8 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Doraemomo9 小时前
数据结构-环形链表
java·数据结构·链表
Forever Nore10 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考11 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX12 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面12 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号13 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽13 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI13 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
MC皮蛋侠客14 小时前
Redis 系列(一):全景与最小闭环——从 `SET` 命令到内存数据结构
数据结构·数据库·redis