算法:除自身以外数组的乘积

428 阅读1分钟
作者: 成北
公众号: 前端下饭菜

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

提示:题目数据保证数组之中任意元素的全部前缀元素和后缀的乘积都在32位整数范围内。
说明:请不要使用除法,且在o(n)时间复杂度内完成此题

最Low版本如下,虽然实现了功能,但与要求不符,不能使用除法,除法运算也是不受待见的。

*/***
** @param {number*[] *} nums*
** @return {number*[] *}*
**/*
var productExceptSelf = function(nums) {
    if (!nums || !nums.length) {
        throw new Error('nums必须为数组且长度大于1.')
    }
    var output = new Array(nums.length), total = 1

    for (let index = 0; index < nums.length; index++) {
        total *= nums[index]
    }

    for (let index = 0; index < nums.length; index++) {
        output[index] = total / nums[index]
    }

    return output
};

var output = productExceptSelf([1, 2, 3, 4])
console.log(output)

想到另外一种方法,两次循环,但时间复杂到达到O(n2),也不符合要求

for (let index = 0; index < nums.length; index++) {
    output[index] = 1
    for (let index2 = 0; index2 < nums.length; index2++) {
        if (index !== index2) {
            output[index] *= nums[index2]
        }
    }
}

想想最Low版本,主要问题是使用了除法,那有没有其他办法代替?可以考虑两次遍历,分别从前后往后、从后往前遍历,计算出前驱乘积和后驱乘积,对应索引的两个乘积再相乘即为满足题目的结果,时间复杂度为O(n)满足要求,由于借助了output存储中间结果,所以空间复杂度只有O(1),声明了一个变量result。

var output = new Array(nums.length), result = 1
output[0] = 1

// 从前往后遍历,output只乘了前驱积
for (let index = 1; index < nums.length; index++) {
    result *= nums[index - 1]
    output[index] = result
}

result = 1
// 从后往前遍历,output补上后驱乘积
for (let index = nums.length - 2; index >= 0; index--) {
    result *= nums[index + 1]
    output[index] *= result
}