【leetcode】238. 除自身以外数组的乘积

36 阅读2分钟

leetcode-238.png

题目要求不能用除法,按照暴力思路来,那时间复杂度就到了n*n,这个也不符合题意

先来看下之前写的一个解法
这里的解法,有点类似于前缀和的意思,分别把从左往右以及从右往左的乘积计算出来,最后对应位置进行相乘即可,注意处理边界条件即可(22行以及24行代码)。

class Solution {
  public int[] productExceptSelf(int[] nums) {
    int len = nums.length;
    int[] res = new int[len];
    if (len == 1) {
      return nums;
    }
    int[] left = new int[len];
    int[] right = new int[len];
    left[0] = nums[0];
    right[len - 1] = nums[len - 1];
    for (int i = 1; i < len; ++i) {
      // 1 2 3 4 nums
      // 1 2 6 24 left
      left[i] = nums[i] * left[i - 1];
    }
    for (int j = len - 2; j >= 0; --j) {
      // 24 24 12 4 right
      right[j] = nums[j] * right[j + 1];
    }
    for (int k = 0; k < len; ++k) {
      if (k == 0) {
        res[k] = right[k + 1];
      } else if (k == len - 1) {
        res[k] = left[len - 2];
      } else {
        res[k] = left[k - 1] * right[k + 1];
      }
    }
    return res;
  }
}

这里的解法也是跟上面相似,只不过空间复杂度没有上面的高。
先处理从左往右的,除开本身的乘积,然后处理从右往左的

var productExceptSelf = function (nums) {
    let len = nums.length
    let res = new Array(len).fill(1)
    let leftTmp = 1
    for (let i = 0; i < len; ++i) {
        res[i] = leftTmp
        leftTmp *= nums[i]
    }
    let rightTmp = 1
    for (let i = len - 1; i >= 0; --i) {
        // 注意这里的处理,需要与右边的相乘
        res[i] *= rightTmp
        rightTmp *= nums[i]
    }
    return res
};

对于测试用例[1,2,3,4]
第一轮计算leftTmp之后有 res = [1, 1, 2, 6]
然后计算第二轮for

  • 第 1 步i = 3):
    • res[3] *= rightTmp = 6 * 1 = 6
    • 更新 rightTmp = rightTmp * nums[3] = 1 * 4 = 4
    • 此时 res = [1, 1, 2, 6]
  • 第 2 步i = 2):
    • res[2] *= rightTmp = 2 * 4 = 8
    • 更新 rightTmp = rightTmp * nums[2] = 4 * 3 = 12
    • 此时 res = [1, 1, 8, 6]
  • 第 3 步i = 1):
    • res[1] *= rightTmp = 1 * 12 = 12
    • 更新 rightTmp = rightTmp * nums[1] = 12 * 2 = 24
    • 此时 res = [1, 12, 8, 6]
  • 第 4 步i = 0):
    • res[0] *= rightTmp = 1 * 24 = 24
    • 更新 rightTmp = rightTmp * nums[0] = 24 * 1 = 24
    • 此时 res = [24, 12, 8, 6]