【每日一题】LeetCode. 152. 乘积最大子数组

每日一题,防止痴呆 = =

一、题目大意

给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
【每日一题】LeetCode. 152. 乘积最大子数组_第1张图片
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-product-subarray

二、题目思路以及AC代码

一开始看到这道题,这不动态规划吗,O(n)就出来了,然后发现我那个动态规划没有考虑负负得正的情况 = =

思路

这道题实际的思路也确实是动态规划,只不过需要考虑负负得正的情况,这样的话,我们可以定义dp_max[i]表示以第i个元素为结尾的子数组中最大乘积是多少,然后很自然的我们会先想到一个表达式,dp_max[i] = max(dp_max[i-1] * nums[i], nums[i]),这里能成立也是因为是求连续子数组,但是这个表达式没有考虑到nums[i]为负数的情况,比如给定数组 -2,3,-4,那么这个递推式就只能得到结果为3。

对于负数的情况,那么我们其实就是在计算dp_max[i]的时候,需要多考虑一种情况,就是以i-1为结尾的子数组中乘积的最小值,因为负数与越小的数相乘,得到的乘积越大,通过上述的叙述,最小值也需要一个dp过程来求,所以其实就是同时求解两个dp,然后dp_max中的最大值即是结果。

这里面由于求解第i个状态时只利用了第i-1个状态,所以可以用滚动数组来进行空间优化,即用一个变量保存即可。

AC代码:

下面给出AC代码:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n_size = nums.size();

        if (!n_size) return 0;
        int dp_max = nums[0];
        int dp_min = nums[0];
        int max_val = dp_max;
        for (int i=1;i<n_size;i++) {
            int tmp_max = dp_max;
            dp_max = max(dp_max * nums[i], max(dp_min * nums[i], nums[i]));
            dp_min = min(tmp_max * nums[i], min(dp_min * nums[i], nums[i]));
            max_val = max(max_val, dp_max);
        }

        return max_val;
    }
};

如果有问题,欢迎大家指正!!!

你可能感兴趣的:(每日一题)