Leetcode 152 穷举法时间超时

来源:1-5 大厂面试为什么总考算法?

甲骨文_0001

2022-10-31

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxProduct = function(nums) {
    let arr = []; // 存放所有连续子数组的乘积

    // nums是否包含有0, 说明乘积肯定有0
    if( nums.includes(0) ){
        arr.push(0); 
    }

    for( let i = 0; i < nums.length; i ++ ){
        if( nums[i] == 0 ){
            continue;
        }
        for( let j = i; j < nums.length; j ++ ){
            if( nums[j] == 0 ){
                break;
            }
            let product = 1;
            // 连续子数组的乘积
            for( let k = i; k <= j; k ++ ){
                product *= nums[k];
            } // for k
            arr.push(product);
        } // for j
    } // for i

    arr.sort((a, b)=>b-a); // 从大到小排序
    return arr[0];
};

老师,这道题目面试的时候我碰上了,我给出了如上的穷举法,起码是通过了考查。但是在leetcode的用例规模下,超时了,我有看您的答案,只是用了一遍for循环就好了,没看太懂。。。。

写回答

1回答

liuyubobobo

2022-10-31

首先,乘积最大的连续子数组内一定不能有 0。一旦有 0,乘积归 0。所以先将整个数组划分成不包含 0 的若干段,处理每一段,看在每一段上得到的最大乘积是多少。


下面,我们面对一个数组,这个数组中不包含 0,其能获得的最大的连续的乘积是多少?


有如下结论:最大的连续乘积所对应的子数组,或者是这个数组的一个前缀,或者是这个数组的一个后缀,而不可能是这个数组的中间一段。


为什么?我们可以用反证法来看:

假设这个数组的最大乘积对应的连续数组,既不是前缀,又不是后缀,是中间的一段。那么这段子数组前面也有元素,后面也有元素。

首先,这个子数组前后的元素都不可能为正数。因为如果是正数,肯定可以把这个正数包含进来,形成一个乘积更大的子数组。

那么,这个子数组前后就只有可能都是负数。但如果前后都是负数,我们就可以把这两个负数都包含进来,负负得正,形成一个乘积更大的子数组。

不管怎样都矛盾。所以,这个子数组不可能是中间的一段,只能或者是一个前缀,或者是一个后缀。


我们可以枚举一个数组的所有前缀和所有后缀的乘积,找最大的,复杂度是 O(n) 的。


继续加油!:)


1
3
甲骨文_0001
嗯嗯 您讲完 我自己清晰多了,谢谢老师:)
2022-10-31
共3条回复

玩转算法面试-- Leetcode真题分门别类讲解

课程配套大量BAT面试真题,高频算法题解析,强化训练

7410 学习 · 1150 问题

查看课程