除自身以外的乘积数组(力扣第238题)

题目

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

示例:

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

提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。

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

 

分析

  不能使用除法,而且时间复杂度是O(n) ,那么暴力循环就不能使用了。所以就要通过发现规律进行解决了。假设一个数组的元素为m0,m2,m3,……,mn-1 ,按照题意,结果数组中:

    num0 = m1 * m2 * m3 * ……mn-1

    num1 = m0 * m2 * m3 * ……mn-1

    num2 = m0 * m1 * m3 * ……mn-1

    num3 = m0 * m1 * m2 * ……mn-1

      ……

    numn-1 = m0 * m2 * m3 * ……mn-2

  通过观察以上的式子,会发现结果数组中,它的每个结果都是由两部分乘积组成的:

    比如第i个结果,它对应了原始数组中除了第i个数以外其他所有数的乘积,

    这个结果的乘积因子都是原始数组中除第i个数以外的元素,那么可以分为两个部分,即一部分因子在原始数组中位于第i个数的前面,另一部分位于第i个数的后面

  那么这些我们在求结果数组中的每一个数的时候,就可以考虑分成两步求:

    第一步求位于第i个数左边的因子乘积,这个可以通过向左遍历原始数组,然后累乘求出第i个数的左边所有数的乘积;

    第二步求位于第i个数右边的因子乘积,这个可以通过向右遍历原始数组,然后累乘求出第i个数的右边所有数的乘积

    而对于第0个数和第n-1个数,它们都只有单侧的因子乘积,那么我们向左遍历完,就能求出结果数组最后一个元素的结果,向右遍历完,也可以求出结果数组中的第一个结果,但是注意,结果数组初始化时,要将第一个值初始化为1,否则会求出0这个结果;

  我们定义一个结果数组,两个累乘变量即left_product和right_product,分别表示求左边因子乘积时的累乘结果,和求右边乘积时的累乘结果。因为首尾两个数都只有单侧因子,所以我们分别从第1个和第n-2个开始求单侧因子乘积

代码如下:

    public int[] productExceptSelf(int[] nums) {

        int n = nums.length;
        int[] res = new int[n];
        if (n == 2){
            res[0] = nums[1];
            res[1] = nums[0];
            return res;
        }

        int left_product = 1;
        res[0] = 1;
        for (int i = 1; i < n; i++) {
            left_product *= nums[i-1];
            res[i] = left_product;
        }
        int right_product = 1;

        for (int i = n-2; i >=0 ; i--) {
            right_product *= nums[i+1];
            res[i] *= right_product;
        }

        return res;
    }

 

posted @ 2020-06-09 23:01  有心有梦  阅读(196)  评论(0编辑  收藏  举报