LeetCode 238. 除自身以外数组的乘积 问题分析+解析

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

问题概述

给定一个整数数组 nums,返回一个数组 answer,其中 answer[i] 等于 nums 中除 nums[i] 之外其余所有元素的乘积。要求不能使用除法,且时间复杂度为 O (n)。

核心思路:前缀与后缀乘积的结合

解决问题的关键是将「除自身以外的乘积」拆分为两部分:

  • 左侧乘积:当前元素左边所有元素的乘积(不包含自身)

  • 右侧乘积:当前元素右边所有元素的乘积(不包含自身)

最终结果 answer[i] = 左侧乘积 × 右侧乘积

为了高效计算这两部分,我们引入前缀乘积数组后缀乘积数组

  • 前缀乘积数组 prefix:存储「从数组起点到当前位置的累积乘积」

  • 后缀乘积数组 suffix:存储「从当前位置到数组终点的累积乘积」

详细步骤解析(含实例)

示例数组

nums = [1, 2, 3, 4] 为例,逐步演示计算过程。

1. 计算前缀乘积数组(prefix)

定义prefix[i] 表示 nums[0] × nums[1] × ... × nums[i](包含当前元素)

java 复制代码
prefix[0] = nums[0];  // 第一个元素的前缀乘积就是自身​
for (int i = 1; i < nums.length; i++) {​
    prefix[i] = nums[i] * prefix[i - 1];  // 累积前一个位置的乘积​
}

计算过程

  • prefix[0] = nums[0] = 1

  • prefix[1] = nums[1] × prefix[0] = 2 × 1 = 2

  • prefix[2] = nums[2] × prefix[1] = 3 × 2 = 6

  • prefix[3] = nums[3] × prefix[2] = 4 × 6 = 24

结果prefix = [1, 2, 6, 24]

2. 计算后缀乘积数组(suffix)

定义suffix[i] 表示 nums[i] × nums[i+1] × ... × nums[n-1](包含当前元素)

java 复制代码
suffix[nums.length - 1] = nums[nums.length - 1];  // 最后一个元素的后缀乘积就是自身​
for (int i = nums.length - 2; i >= 0; i--) {​
    suffix[i] = nums[i] * suffix[i + 1];  // 累积后一个位置的乘积​
}

计算过程

  • suffix[3] = nums[3] = 4

  • suffix[2] = nums[2] × suffix[3] = 3 × 4 = 12

  • suffix[1] = nums[1] × suffix[2] = 2 × 12 = 24

  • suffix[0] = nums[0] × suffix[1] = 1 × 24 = 24

结果suffix = [24, 24, 12, 4]

3. 计算最终结果(answer)

核心逻辑

  • 对于第 i 个元素,左侧乘积 = prefix[i-1](若 i > 0

  • 对于第 i 个元素,右侧乘积 = suffix[i+1](若 i < n-1

  • 边界情况:

    • 第一个元素(i=0):左侧无元素,结果 = 右侧乘积(suffix[1]

    • 最后一个元素(i=n-1):右侧无元素,结果 = 左侧乘积(prefix[n-2]

java 复制代码
for (int i = 0; i < nums.length; i++) {​
    if (i == 0) {​
        answer[i] = suffix[i + 1];  // 第一个元素无左侧​
    } else if (i == nums.length - 1) {​
        answer[i] = prefix[i - 1];  // 最后一个元素无右侧​
    } else {​
        answer[i] = prefix[i - 1] * suffix[i + 1];  // 中间元素 = 左 × 右​
    }​
}

计算过程 (以 nums = [1,2,3,4] 为例):

  • i=0answer[0] = suffix[1] = 24

  • i=1answer[1] = prefix[0] × suffix[2] = 1 × 12 = 12

  • i=2answer[2] = prefix[1] × suffix[3] = 2 × 4 = 8

  • i=3answer[3] = prefix[2] = 6

结果answer = [24, 12, 8, 6]

复制代码
nums:   [1,   2,   3,   4]

prefix: [1,   2,   6,  24]  → 从左到右累积

suffix: [24, 24,  12,   4]  → 从右到左累积

answer[i] 计算:

i=0 → 右侧:suffix[1] → 24

i=1 → prefix[0] × suffix[2] → 1×12=12

i=2 → prefix[1] × suffix[3] → 2×4=8

i=3 → 左侧:prefix[2] → 6

复杂度分析

  • 时间复杂度:O (n),仅需 3 次线性遍历(前缀、后缀、结果计算)。

  • 空间复杂度:O (n),需要额外存储前缀和后缀两个数组(可优化至 O (1),但此解法更直观)。

总结

通过前缀乘积和后缀乘积的拆分,我们巧妙避开了除法运算,同时满足了时间复杂度要求。核心思想是将「全局问题」拆解为「左侧局部乘积」和「右侧局部乘积」的组合,这种分治思想在数组类问题中非常常见。

相关推荐
搬砖小匠16 分钟前
SpringBoot 通过自定义注解 + AOP 实现数据字典自动翻译(通用方案)
java·后端
今天AI了吗16 分钟前
【AI智能体】Hermes Agent 从部署到项目实战操作详解
java·人工智能·python·milvus
旖旎夜光21 分钟前
LeetCode 738:单调递增的数字(贪心算法) —— 题解
数据结构·c++·算法·leetcode·贪心算法
青山木28 分钟前
Hot 100 --- 搜索二维矩阵
java·算法·leetcode·矩阵
旖旎夜光30 分钟前
LeetCode 1262:可被三整除的最大和 (贪心算法)—— 题解
数据结构·c++·算法·leetcode·贪心算法
心运软件35 分钟前
基于机器学习的智能邮件分类系统:从数据采集到模型部署全流程实战
人工智能·python·算法·随机森林·机器学习·分类·scikit-learn
CoderYanger44 分钟前
Java EE:9.JVM(课件内容-上篇)
java·jvm·程序人生·面试·职场和发展·java-ee·程序员创富
xiaoqiMikko1 小时前
Spring Cloud Config 这个 CVE 的补丁,Maven Central 上根本没有
java·spring boot
残月心殇 请珍惜枸1 小时前
.NET陷阱之五:奇怪的OutOfMemoryException——大对象堆引起的问题与对策
java·jvm·.net
用户3126874877201 小时前
Spring Boot 配置体系到底怎么加载的?从 application.yml 到 @Conditional 的全链路拆解
java·spring boot