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

优质博文: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】创建左右乘积列表: 我们不能将所有数字的乘积除以给定索引处的数字得到相应的答案,而是利用索引左侧所有数字的乘积和右侧所有数字的乘积(即前缀与后缀)相乘得到答案 。初始化两个数组Left和Right,对于指定的下表i,left[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的大小。预处理L和R数组以及最后的遍历计算都是O(N)的时间复杂度。
空间复杂度: O(N),其中N指的是数组nums的大小。使用了L和R数组去构造答案,L和R数组的长度为数组nums的大小。

【2】空间复杂度O(1)的方法: 由于输出数组不算在空间复杂度内 ,那么我们可以将L或R数组用输出数组来计算。先把输出数组当作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),输出数组不算进空间复杂度中,因此我们只需要常数的空间存放变量。

相关推荐
破芽11 小时前
python知识点整理02
开发语言·python
一木 之林11 小时前
DeepSeek Agent 开发(三)
java·大数据·linux
edtoplort11 小时前
OpenAI紧急叫停GPT-6.1 Astra训练,奥尔特曼为何踩刹车
人工智能·gpt·算法
打工仔折腾 AI11 小时前
Docker镜像分层与卷挂载到底怎么工作:一次文件系统层面的实测分析
运维·人工智能·后端·python·docker·容器·性能优化
denlaku11 小时前
JDK 10 新特性详解
java·开发语言
cfm_291411 小时前
Java常见加密算法全解
开发语言
程序员耄耋11 小时前
JDK21的下载与安装(2025.8.2)
java
墨染天姬11 小时前
【人工智能训练师】python语法二
开发语言·人工智能·python
~木雨11 小时前
Java 线程从生到死:创建三式、六态流转、中断协作与死锁活锁饥饿,一篇讲透
java·java并发·虚拟线程·死锁·线程状态·中断机制
程序员Sunday11 小时前
MCP stdio 与 Streamable HTTP 怎么选,流式消息传到哪里
后端