【动态规划】No. 0152 乘积最大子数组【中等】👉力扣对应题目指路
希望对你有帮助呀!!💜💜 如有更好理解的思路,欢迎大家留言补充 ~ 一起加油叭 💦
欢迎关注、订阅专栏 【力扣详解】谢谢你的支持!
⭐ 题目描述:给你一个整数数组 nums ,找出数组中乘积最大的非空连续子数组,并返回该子数组所对应的乘积
-
该子数组中至少包含一个数字
-
测试用例的答案是一个 32-位 整数
-
示例 :
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6
🔥 思路:采用动态规划,建立 dp 数组,利用前序 dp 数组推导其自身 dp 值
- 以
nums[i]
结尾的非空连续子数组能得到的最大乘积与前序0 ~ i-1
所对应的乘积情况有关
- 实际仅与 i-1 有关,👉 见文末的代码优化版本⛳
参考如上思路,给出详细步骤如下:
步骤一⭐确定 dp 数组含义:一维 dp 数组
dp[i]
的含义为:以nums[i]
结尾的非空连续子数组能得到的[最大乘积项, ⚡最小乘积项]
【💥 重要】
- 不能只保留
最大乘积
项,因为需要应对 负负得正的情况:如对于 nums = [-2, -3, -4],处理i=2
(👉 -4) 位置时,需要前序⚡最小乘积 (最大负数,因为 -4 是负数) 来计算以-4
结尾的非空连续子数组能得到的最大乘积步骤二⭐确定 dp 推导方式:前序 dp 数组推导得到,取如下三种情况的最大、最小值
- 情况一:选择从
nums[i]
新开子数组,乘积对应 nums[i]- 情况二:选择继续前序子数组,为应对负负得正情况,考虑两种乘积情况
- 前序最大乘积项乘以当前值(👉
dp[i-1][0]*nums[i]
)和前序最小乘积项乘以当前值(👉dp[i-1][1]*nums[i]
)步骤三⭐根据 dp 数组含义,初始化 dp 数组:
- 由前序
i-1
推导,所以只需要关注最前面一个数的dp
初值
dp[0]
=[nums[0], nums[0]]
- 根据推导公式,其他位置得初值会被覆盖、任意数均可(本代码中赋值
[0, 0]
)
class Solution:
def maxProduct(self, nums: List[int]) -> int:
dp = [[0, 0] for _ in nums] # ------------------------------------------------- step 1
# 递推公式初始化: # ------------------------------------------------------------ step 3
dp[0] = [nums[0], nums[0]]
result = nums[0]
for i in range(1, len(nums)):
# -------------------------------------------------------------------------- step 2
dp[i][0] = max(nums[i], dp[i-1][0]*nums[i], dp[i-1][1]*nums[i])
dp[i][1] = min(nums[i], dp[i-1][0]*nums[i], dp[i-1][1]*nums[i])
result = max(dp[i][0], result)
return result
⛳ 由于只用到了前面一位的 dp 值:
dp[i-1]
,可进一步压缩dp
为imin, imax
;具体代码如下:
class Solution:
def maxProduct(self, nums: List[int]) -> int:
imin, imax = nums[0], nums[0]
result = nums[0]
for i in range(1, len(nums)):
imin, imax = min(nums[i], imin*nums[i], imax*nums[i]), max(nums[i], imin*nums[i], imax*nums[i])
result = max(imax, result)
return result
希望对你有帮助呀!!💜💜 如有更好理解的思路,欢迎大家留言补充 ~ 一起加油叭 💦
🔥 LeetCode 热题 HOT 100