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

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

中等

提示

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

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。

不要使用除法, 且在 O(n) 时间复杂度内完成此题。

示例 1:

复制代码
输入: nums = [1,2,3,4]
输出: [24,12,8,6]

示例 2:

复制代码
输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

提示:

  • 2 <= nums.length <= 105
  • -30 <= nums[i] <= 30
  • 输入 保证 数组 answer[i]32 位 整数范围内

📝 核心笔记:除自身以外数组的乘积 (左右乘积列表)

1. 核心思想 (一句话总结)

"左边乘积x 右边乘积"。

想知道除了自己以外所有人的乘积,等于 (自己左边所有人的乘积) x (自己右边所有人的乘积)。

💡 直观理解:

不要试图去"剔除"自己(不用除法)。

而是把自己当成分界线,分别计算左半边和右半边的累积结果,最后左右一拍即合。

2. 算法流程 (三步走)
  1. 算左侧 ( pre**):** 从左往右扫,pre[i]0i-1 的乘积。
  2. 算右侧 ( suf**):** 从右往左扫,suf[i]i+1n-1 的乘积。
  3. 合并 ( ans**):** ans[i] = pre[i] * suf[i]

🔍 代码回忆清单 (带注释版)

复制代码
// 题目:LC 238. 除自身以外数组的乘积
class Solution {
    public int[] productExceptSelf(int[] nums) {
        int n = nums.length;
        
        // 1. 计算左侧乘积 (前缀积)
        int[] pre = new int[n];
        pre[0] = 1; // 关键点:最左边元素的左侧没有数字,视为 1
        for (int i = 1; i < n; i++) {
            pre[i] = pre[i - 1] * nums[i - 1]; // 注意是乘 nums[i-1]
        }

        // 2. 计算右侧乘积 (后缀积)
        int[] suf = new int[n];
        suf[n - 1] = 1; // 关键点:最右边元素的右侧没有数字,视为 1
        for (int i = n - 2; i >= 0; i--) {
            suf[i] = suf[i + 1] * nums[i + 1]; // 注意是乘 nums[i+1]
        }

        // 3. 合并结果
        int[] ans = new int[n];
        for (int i = 0; i < n; i++) {
            ans[i] = pre[i] * suf[i]; // 左积 * 右积
        }
        return ans;
    }
}

⚡ 快速复习 CheckList (易错点)

  • \] **边界初始值?** `pre[0]` 和 `suf[n-1]` 必须初始化为 **1**(乘法的单位元)。

    • pre1 开始(因为 0 已知)。
    • sufn-2 开始(因为 n-1 已知)。
  • \] **索引错位?** 计算 `pre[i]` 时乘的是 `nums[i-1]`(它的前一个数);计算 `suf[i]` 时乘的是 `nums[i+1]`(它的后一个数)。

你当前的代码使用了 O(N) 的额外空间(pre 和 suf 数组)。

面试官通常会追问:如何用 O(1) 额外空间(输出数组不计入)?

优化思路:

  1. 先把 ans 数组当做 pre 数组用(先算左侧)。

  2. 不创建 suf 数组,而是用一个变量 R (right) 动态维护右侧乘积。

  3. 从右往左倒着扫,边算 R 边更新 ans

    // 空间优化逻辑概览
    ans[i] = 左侧积; // 先存好左边
    int R = 1;
    for (int i = n-1; i >= 0; i--) {
    ans[i] = ans[i] * R; // 左边 * 右边
    R *= nums[i]; // R 累乘当前值,为下一个做准备
    }

相关推荐
yaoxin5211232 小时前
269. Java Stream API - Map-Filter-Reduce算法模型
java·python·算法
招风的黑耳2 小时前
智慧养老项目:当SpringBoot遇到硬件,如何优雅地处理异常与状态管理?
java·spring boot·后端
rockmelodies2 小时前
亿赛通脚本远程调试配置技巧
java·亿赛通·debug调试
Bruce_kaizy2 小时前
C++树形数据结构————树状数组、线段树中“逆序对”的问题
开发语言·数据结构·c++
❥ღ Komo·2 小时前
K8s蓝绿发布实战:零停机部署秘籍
java·开发语言
FMRbpm3 小时前
用栈实现队列
数据结构·c++·新手入门
小安同学iter3 小时前
天机学堂-排行榜功能-day08(六)
java·redis·微服务·zset·排行榜·unlink·天机学堂
hgz07103 小时前
Spring Boot Starter机制
java·spring boot·后端