【春节篇】LeetCode 热题 100 之 238.除了自身以外数组的乘积

祝大家新年快乐!!!身体健康!!!万事顺意!!!

核心思路

题目要求返回数组 answer,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积,且禁止使用除法,时间复杂度需为 O (n)。

核心解法是前缀积 + 后缀积

  1. 前缀积数组prefix[i] 表示 nums[0] * nums[1] * ... * nums[i-1](即 nums[i] 左侧所有元素的乘积)。
  2. 后缀积数组suffix[i] 表示 nums[i+1] * nums[i+2] * ... * nums[n-1](即 nums[i] 右侧所有元素的乘积)。
  3. 最终结果:answer[i] = prefix[i] * suffix[i]

解法一:使用前缀积和后缀积数组(空间复杂度 O (n))

实现

复制代码
public int[] productExceptSelf(int[] nums) {
    int n = nums.length;
    int[] prefix = new int[n];
    int[] suffix = new int[n];
    int[] answer = new int[n];

    // 计算前缀积:prefix[i] 是 nums[0..i-1] 的乘积
    prefix[0] = 1;
    for (int i = 1; i < n; i++) {
        prefix[i] = prefix[i - 1] * nums[i - 1];
    }

    // 计算后缀积:suffix[i] 是 nums[i+1..n-1] 的乘积
    suffix[n - 1] = 1;
    for (int i = n - 2; i >= 0; i--) {
        suffix[i] = suffix[i + 1] * nums[i + 1];
    }

    // 结果 = 前缀积 * 后缀积
    for (int i = 0; i < n; i++) {
        answer[i] = prefix[i] * suffix[i];
    }
    return answer;
}

复杂度分析

  • 时间复杂度:O (n),三次线性遍历。
  • 空间复杂度:O (n),使用了两个额外数组。

解法二:原地优化(空间复杂度 O (1),进阶要求)

思路

  1. 先用 answer 数组存储前缀积。
  2. 用一个变量 right 从右向左遍历,实时维护当前位置的后缀积,直接乘到 answer 上,从而省去后缀积数组。

实现

复制代码
public int[] productExceptSelf(int[] nums) {
    int n = nums.length;
    int[] answer = new int[n];

    // 第一步:计算前缀积,存入 answer 数组
    answer[0] = 1;
    for (int i = 1; i < n; i++) {
        answer[i] = answer[i - 1] * nums[i - 1];
    }

    // 第二步:从右向左遍历,用变量 right 维护后缀积
    int right = 1;
    for (int i = n - 1; i >= 0; i--) {
        answer[i] = answer[i] * right;
        right = right * nums[i]; // 更新后缀积,包含当前元素
    }

    return answer;
}

示例验证(nums = [1,2,3,4]):

  1. 前缀积阶段:answer = [1, 1, 2, 6]
  2. 从右向左遍历:
    • i=3: answer[3] = 6 * 1 = 6, right = 1 * 4 = 4
    • i=2: answer[2] = 2 * 4 = 8, right = 4 * 3 = 12
    • i=1: answer[1] = 1 * 12 = 12, right = 12 * 2 = 24
    • i=0: answer[0] = 1 * 24 = 24, right = 24 * 1 = 24
  3. 最终结果:[24, 12, 8, 6],与示例一致。

复杂度分析

  • 时间复杂度:O (n),两次线性遍历。
  • 空间复杂度:O (1),仅使用常数额外空间(输出数组不计入)。

总结

  • 基础解法( 左右乘积列表**)**:通过前缀积和后缀积数组,清晰地将问题拆解为 "左侧乘积 × 右侧乘积",易于理解。
  • 进阶解法:通过原地复用数组和变量,将空间复杂度优化到 O (1),是面试中的推荐写法。
相关推荐
铸人2 小时前
再论自然数全加和 - 质数螺旋及其生成程序
数学·算法·数论·复数
散峰而望2 小时前
【算法竞赛】堆和 priority_queue
开发语言·数据结构·c++·算法·贪心算法·动态规划·推荐算法
WarPigs2 小时前
UI显示任务目的地标记的方法
算法·ui
蚊子码农2 小时前
算法题解记录-560和为k的子数组
算法
alexwang2112 小时前
B2007 A + B 问题 题解
c++·算法·题解·洛谷
重生之后端学习2 小时前
46. 全排列
数据结构·算法·职场和发展·深度优先·图论
wostcdk2 小时前
数论学习1
数据结构·学习·算法
我是中国人哦(⊙o⊙)3 小时前
我的寒假作业
人工智能·算法·机器学习
Zik----3 小时前
Leetcode2 —— 链表两数相加
数据结构·c++·leetcode·链表·蓝桥杯