作者:晓宜🌈🌈🌈
携程javaer,阿里云专家博主,csdn后端优质创作者 ❤️❤️❤️
今天给大家带来一道动态规划的算法题,这也是我去年面试字节的时候面试官给我出的一道题,当时给我难倒了
希望今天的分享对大家秋招找工作有帮助🍗🍗🍗
题目
https://leetcode.cn/problems/maximum-product-subarray/description/
给你一个整数数组 nums
,请你找出数组中乘积最大的非空连续子数组
(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
测试用例的答案是一个 32-位 整数。
示例 1:
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: nums = [-2,0,-1] 输出: 0 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
思路
我们考虑输入的数组,如果一个数组 nums中,前 i 个是正数,但是后面 i + 1 的位置出现了一个负数,那么对于数组 nums[0:i+1]中,最大的非空连续子数组就不应该包含这个负数,但是如果这个负数后面还有一个负数,那么这两个负数就应该相乘,成为一个正数,然后和前面的所有正数相乘,这才是真正的最大值。
所以,我们的最大的非空连续子数组的乘积来自前面最大的正数或是前面最小的负数,我们在递推的过程中要记录这两个数字。
我们定义f[i]表述以i为结尾的数组的最大的非空连续子数组的乘积,那么我们可以得到这样一个公式:
我们观察最大乘积值fmax的转移方式,如果ai是正数,我们计算 fmax(i-1)*ai;如果ai是负数,那么那么我们计算 fmin(i-1)*ai,此时是如果ai是负数的最大乘积值,两者比较取最大值,就是当前fmax(i)的值
对于fmin(i)而言也是相同的的计算逻辑。
我们取f数组的最大值,那就是我们的答案
复杂度
- 时间复杂度: O(n),因为我们只需遍历数组一次。
- 空间复杂度: O(1),因为我们只使用了常数个额外空间。
Code
class Solution:
def maxProduct(self, nums: List[int]) -> int:
n = len(nums)
ans = -1000000
minv = maxv = 1
for i in range(n):
if nums[i] < 0:
minv,maxv = maxv,minv
maxv = max(maxv*nums[i],nums[i])
minv = min(minv*nums[i],nums[i])
ans = max(ans,maxv)
return ans
这个代码通过在遍历数组时动态更新最小乘积和最大乘积,并在每一步更新全局最大乘积,从而找到最大的子数组乘积。