LeetCode 238:除自身以外数组的乘积(Java实现)

题目描述

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

  1. 时间复杂度为 O(n)
  2. 不能使用除法
  3. 空间复杂度为 O(1)(不包含输出数组)

解决思路

由于不能使用除法,直接计算每个位置左右两侧的乘积是一种高效的方法。具体步骤如下:

1. 两次遍历法(左右乘积法)

  • 第一次遍历(左→右):计算每个元素左侧所有元素的乘积,并存储在结果数组 answer 中。
  • 第二次遍历(右→左):维护一个变量 rightProduct,动态计算当前元素右侧所有元素的乘积,并与左侧乘积相乘,得到最终结果。

2. 核心思想

  • 空间优化:直接复用结果数组 answer,避免额外空间。
  • 分治思想:将问题拆解为“左侧乘积”和“右侧乘积”两部分,分别求解后合并。

Java代码实现

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int n = nums.length;
        int[] answer = new int[n];
        
        // 1. 计算左侧乘积(answer[i] = nums[0] * nums[1] * ... * nums[i-1])
        answer[0] = 1; // 第一个元素左侧无元素,初始化为1
        for (int i = 1; i < n; i++) {
            answer[i] = answer[i - 1] * nums[i - 1];
        }
        
        // 2. 计算右侧乘积并合并结果
        int rightProduct = 1; // 最后一个元素右侧无元素,初始化为1
        for (int i = n - 1; i >= 0; i--) {
            answer[i] *= rightProduct; // 左侧乘积 * 右侧乘积
            rightProduct *= nums[i];     // 更新右侧乘积
        }
        
        return answer;
    }
}

复杂度分析

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

示例说明

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

步骤分解

  1. 左侧乘积计算

    • answer[0] = 1(左侧无元素)
    • answer[1] = answer[0] * nums[0] = 1 * 1 = 1
    • answer[2] = answer[1] * nums[1] = 1 * 2 = 2
    • answer[3] = answer[2] * nums[2] = 2 * 3 = 6
    • 此时 answer = [1, 1, 2, 6]
  2. 右侧乘积计算与合并

    • 初始化 rightProduct = 1
    • i=3answer[3] *= 16*1=6,更新 rightProduct = 1*4=4
    • i=2answer[2] *= 42*4=8,更新 rightProduct = 4*3=12
    • i=1answer[1] *= 121*12=12,更新 rightProduct = 12*2=24
    • i=0answer[0] *= 241*24=24,更新 rightProduct = 24*1=24
    • 最终结果:answer = [24, 12, 8, 6]

注意事项

  • 边界条件:当输入数组长度为1时,直接返回 [1]
  • 避免溢出:题目未明确说明数据范围,但实际应用中需考虑乘积溢出问题。

总结

通过两次遍历分别计算左右两侧的乘积,既避免了除法,又优化了空间复杂度。该方法适用于需要前后缀计算的场景(如“接雨水”问题)。关键在于分步拆解问题,复用结果数组减少空间占用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的小白菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值