题目描述
解题方法
暴力搜索
class Solution:
def maxProduct(self, nums: List[int]) -> int:
dp = [[nums[i] for i in range(len(nums))] for j in range(len(nums))]
max_product = dp[0][0]
for i in range(len(nums)):
dp[i][i] = nums[i]
max_product_i = dp[i][i]
for j in range(i+1,len(nums)):
dp[i][j] = dp[i][j-1] * nums[j]
max_product_i = max(max_product_i,dp[i][j])
max_product = max(max_product_i,max_product)
return max_product
时间复杂度 O ( n 2 ) O(n^2) O(n2)
动态规划
对于子数组问题按照最大子序和中的思路,定义dp[i] 为以i为结尾的子串的某种状态。
- 尝试1:
按照最大子序和那样定义状态dp[i]为以i为结尾的子串的最大乘积。
状态转移为: dp[i] = max(dp[i-1]*nums[i], nums[i])。
运行后发现这种状态转移不正确,如果当前的nums[i]为负数,以当前nums[i]为结尾的最大子串乘积此时有可能为该负数乘以该元素之前最小的负乘积,不一定是nums[i]乘以之前元素的最大乘积。 - 尝试2:
- 状态定义:同时定义了以i为结尾的子串的最大乘积dp_max[i]和以i为结尾的子串最小乘积dp_min[i].
- 状态转移:
- dp_max[i] = max(nums[i] * dp_max[i-1], nums[i] * dp_min[i-1], nums[i])
- dp_min[i] = min(nums[i] * dp_max[i-1], nums[i] * dp_min[i-1], nums[i])
- max_product = max(max_product, dp_max[i])
class Solution:
def maxProduct(self, nums: List[int]) -> int:
dp_min = [nums[i] for i in range(len(nums))]
dp_max = [nums[i] for i in range(len(nums))]
max_product = nums[0]
for i in range(1, len(nums)):
max_i = nums[i] * dp_max[i-1]
min_i = nums[i] * dp_min[i-1]
dp_max[i] = max(max_i,min_i,nums[i])
dp_min[i] = min(max_i,min_i,nums[i])
max_product = max(max_product,dp_max[i])
return max_product
反思总结
- 对于子串问题可定义状态dp[i]为以nums[i]结尾的子串的某种状态
- 该问题比最大子序和问题加升了难度。最大自序和问题只要每一状态的子序和为最大对于后面的状态就是最优的选择,可以认为是单调的。而最大乘积问题,每一状态的子序和最大时,后续状态不一定在之前的最大乘积状态下取得最大,例如有可能后面出现一负数,乘以前面子串的最小负乘积,负负得正这种情况下取得最大。所以每个状态下也存储最小的乘积。
- 对于max(dp[i-1]+nums[i], nums[i])的理解:
- 当前的状态不一定是上一状态的最优解+当前元素就是最优的,对于上一状态的结果为负数情况,加上当前元素后更小了,此时只有当前元素时结果最优。