除自身以外数组的乘积


目录

1 题目描述

2 题目分析

3 代码实现


1 题目描述

给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。

示例:

输入: [1,2,3,4]
输出: [24,12,8,6]

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

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


2 题目分析

       如果没有题目中的限制,那么res[i]=A[0]*A[1]*...*A[n]/A[i]就能很容易的求出答案了,但是这里明确要求时间复杂度为O(N),空间复杂度为O(1),那该怎么做呢?

       实际上,对于每一个数,除其自身以外数组的乘积等于左边所有数的乘积*右边所有数的乘积,用seq[i]表示nums[i]左边所有数的乘积,rev[i]表示nums[i]右边所有数的乘积,那么很显然res[i]=sea[i]*rev[i],这个过程用图来描述如下:

                       除自身以外数组的乘积_第1张图片

        如图所示,seq数组为顺序乘积,rev数组为逆序乘积,seq[i]= \prod_{0}^{i-1}nums[i]rev[i]= \prod_{i+1}^{len-1}nums[i],其中len为nums数组的长度,需要注意的是,对于seq数组,seq[0]由于nums[0]其左边没有元素,因此初始为1,rev[len-1]由于nums[len-1]右边也没有元素,因此也初始化为1。

       而对于seq数组和rev数组,遍历一次nums数组即可将二者全部赋值,再遍历一次即可将res得出来,不过这样时间复杂度为O(2N)近似为O(N),但是很明显空间复杂度也近似为O(N)了,与题意不符,那么该怎么改进呢?

       实际上,我们可以发现,seq数组和rev数组的元素都是迭代前面或后面累积乘积计算的,因此可以考虑用变量来替换掉两个数组。

       定义变量seqMul和revMul分别表示顺序累积乘积和逆序累积乘积,分别从0和len-1开始累积。在遍历nums数组到nums[i]时,seqMul也从0到i-1累积相乘得到了nums[i]左边所有数的乘积,因此可以先将seqMul保存在res[i]中;而另一方面,revMul也从len-1到len-2+i累计相乘得到了nums[len-1-i]右边所有数的乘积,因此先将revMul保存在res[len-1-i]中。然后继续遍历,

       当遍历到nums[len-1-i]时,seqMul也从0到len-2-i累积相乘得到了nums[len-1-i]左边所有数的乘积,而此时res[len-1-i]中保存着前面遍历得到的nums[len-1-i]右边所有数的乘积,此时再将res[len-1-i]*seqMul,得到的便是nums[len-1-i]左右两边所有数的乘积,也就是最终所要求的;而另一方面的revMul也从len-1到i+1累计相乘得到了nums[i]右边所有数的乘积,而此时res[li]中保存着前面遍历得到的nums[i]左边所有数的乘积,此时再将res[i]*revMul,得到的便是nums[i]左右两边所有数的乘积,也就是最终所要求的.....

       通过这样的方法,就可以只在一次遍历后得到结果,时间复杂度为O(N),空间复杂度只是定义了几个变量,因此为O(1)。

代码实现如下:


3 代码实现

vector productExceptSelf(vector& nums) {
        
        int len=nums.size();

        vectorres(len,1);
        
        int seqMult=1; 
        int revMult=1;
        
        for(int i=1;i

 

你可能感兴趣的:(LeetCode)