除自身以外数组的乘积[中等]

优质博文:IT-BLOG-CN

一、题目

给你一个整数数组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

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

进阶:你可以在O(1)的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组 不被视为 额外空间。)

二、代码

【1】创建左右乘积列表: 我们不能将所有数字的乘积除以给定索引处的数字得到相应的答案,而是利用索引左侧所有数字的乘积和右侧所有数字的乘积(即前缀与后缀)相乘得到答案 。初始化两个数组LeftRight,对于指定的下表ileft[i]代表i左侧所有数据的乘积,right[i]代表i右侧所有数据的乘积。我们利用循环将数据填充到lfet[]right[]数组中,然后将left[i]right[i]相乘就是i的左右乘积。

java 复制代码
class Solution {
    public int[] productExceptSelf(int[] nums) {
        if (nums == null || nums.length == 0) {
            return null;
        }

        // 我们使用数组,也就是当前数字的left[] 和 right[] 数组,分别存储左右两边的和;
        int len = nums.length;
        int res[] = new int[len];
        int left[] = new int[len];
        int right[] = new int[len];
        // 第一个数之前的数的乘积为1,所以先给个默认值
        left[0] = 1;
        for (int i = 1; i < len; i++) {
            // left 中保存的是i之前所有数的乘积
            left[i] = left[i - 1] * nums[i - 1];
        }
        // 最有边的数也保存为1
        right[len - 1] = 1;
        for (int i = len - 2; i >= 0; i--) {
            right[i] = right[i + 1] * nums[i + 1];
        }

        for (int i = 0; i < len; i++) {
            res[i] = left[i] * right[i];
        }
        return res;
    }
}

时间复杂度: O(N),其中N指的是数组nums的大小。预处理LR数组以及最后的遍历计算都是O(N)的时间复杂度。
空间复杂度: O(N),其中N指的是数组nums的大小。使用了LR数组去构造答案,LR数组的长度为数组nums的大小。

【2】空间复杂度O(1)的方法: 由于输出数组不算在空间复杂度内 ,那么我们可以将LR数组用输出数组来计算。先把输出数组当作L数组来计算,然后再动态构造R数组得到结果。

java 复制代码
class Solution {
    public int[] productExceptSelf(int[] nums) {
        if (nums == null || nums.length == 0) {
            return null;
        }

        // 因为返回的数组可以不算在空间复杂度中,所以可以作为临时变量存放left[]数据
        int len = nums.length;
        int res[] = new int[len];
                // // 第一个数之前的数的乘积为1,所以先给个默认值
        res[0] = 1;
        for (int i = 1; i < len; i++) {
            // left 中保存的是i之前所有数的乘积
            res[i] = res[i - 1] * nums[i - 1];
        }

        // 然后从后向前变量,通过变量 right保存前几位数的乘积
        int right = 1;
        for (int i = len - 1; i >= 0; i--) {
            res[i] *= right;
            // 放在返回值的后面,就相当于i + 1
            right *= nums[i];
        } 
        return res;
    }
}

时间复杂度: O(N),其中N指的是数组nums的大小。分析与方法一相同。
空间复杂度: O(1),输出数组不算进空间复杂度中,因此我们只需要常数的空间存放变量。

相关推荐
天下无敌笨笨熊1 分钟前
C#Modbus串口开发心得
开发语言·c#
电商API_180079052472 分钟前
电商商品价格监控工具淘宝京东商品价格抓取API项目实操分享
java·大数据·开发语言·前端·数据挖掘
zzzll11113 分钟前
深度剖析:HashMap 并发死循环与 ConcurrentHashMap 两代演进全解
java·开发语言
如意猴5 分钟前
【C++】001--C++入门(1)
开发语言·c++
秋名RG14 分钟前
2026/5/27 生产事故复盘与整改方案
java
hetao173383715 分钟前
2026-09-01~09-04 hetao1733837 的刷题记录
c++·算法
传奇开心果编程29 分钟前
【Rust入门知识点学与练】第10课:Option 和 Result(错误处理入门)
开发语言·学习·rust
Evand J33 分钟前
【MATLAB例程,图像滤波5】 反谐波均值滑动窗口滤波(CHMF)图像降噪与质量评价,附代码下载链接
图像处理·算法·计算机视觉·matlab·均值算法·滑动窗口滤波·均值滑动
码事漫谈40 分钟前
一天搭出 80% 的 Agent,然后卡在 95% 到死
后端
leonkay43 分钟前
C# 锁机制——【2】深入原理
开发语言·后端·spring·c#·个人开发