LeetCode--152. 最大乘积子数组【DP】

85 阅读2分钟

152. 乘积最大子数组


正文

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续 子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

测试用例的答案是一个 32-位 整数。

如题给定一个数组,求连续子数组最大乘积

第一次看见这道题的思路是用动态规划,计算前缀乘积,但是这样一来时间复杂度很高,前缀为0以及负数的情况很难处理。

更好的思路应该是同时统计前缀的最大值和最小值,因为最小值在遇到负数之后会变成最大值,而最大值会变成最小值,通过max嵌套来处理前缀为0的情况,下面是未经优化的代码:

vfunc maxProduct(nums []int) int {
    n := len(nums)
    maxF := make([]int, n)
    minF := make([]int, n)
    
    maxF[0] = nums[0]
    minF[0] = nums[0]
    
    for i := 1; i < n; i++ {
        maxF[i] = max(maxF[i-1]*nums[i], max(nums[i], minF[i-1]*nums[i]))
        minF[i] = min(minF[i-1]*nums[i], min(nums[i], maxF[i-1]*nums[i]))
    }
    
    ans := maxF[0]
    for i := 1; i < n; i++ {
        ans = max(ans, maxF[i])
    }
    
    return ans
}

时间和空间复杂度均为O(N),但是我们可以发现,maxF和minF中的每个数据都只是在计算后一个数据的时候才用到了一次,最后则是统计最大值,所以在这里我们可以进行优化,只需要在计算maxF和minF的时候直接计算ans即可,这样就可以将空间复杂度优化为O(1),代码如下:

func maxProduct(nums []int) int {
    maxF, minF, ans := nums[0], nums[0], nums[0]

    for i := 1; i < len(nums); i++ {
        mx, mn := maxF, minF
        maxF = max(mx * nums[i], max(nums[i], mn * nums[i]))
        minF = min(mn * nums[i], min(nums[i], mx * nums[i]))
        ans = max(maxF, ans)
    }

    return ans
}

结语

最近决定要稍微多写一点题解了,只要是第一次写错的,争取都写一遍吧, 欢迎交流学习