题目描述
思路
方法一: 暴力 - 时间复杂度 O ( n ) O(n) O(n)
0
在数组中是个特殊元素,因为任何元素和0
相乘都为0
,(DP思路没写出来时)我想着以0
为切分点,将原数组切分成一些子数组,这些子数组中不包含0
,然后单考虑所有的子数组:
- 若子数组中不含负数,或者包含偶数个负数,那么该子数组的最大值就是 所有元素的乘积
- 若子数组中含有奇数个负数,易证:该子数组的最大值是 最后一个负数之前的所有元素的乘积(不含最后一个负数) 或 第一个负数之后的所有元素的乘积(不含第一个负数)。
- 然后取各个子数组中的最大值即可
例如 对于[1,2,3,4,0, 5,-6,-7,8,-9],
- 被分为[1,2,3,4] 和 [5,-6,-7,8,-9] 两个子数组
- 其中 [5,-6,-7,8,-9] 的最大值是 [5,-6,-7,8] 或者 [-7,8,-9] 的乘积
class Solution:
def maxProduct(self, nums: List[int]) -> int:
def handle(left, right): # 计算一个不含0的整数数组的最大值
if left == right:
self.res = max(self.res, nums[left])
return
cnt = 0
mid = 1
first_index, end_index = 0, 0
for i in range(left, right+1):
mid *= nums[i]
if nums[i] < 0:
cnt += 1
if cnt == 1:
first_index = i
end_index = i
if cnt % 2: # 为奇数
key = 1
for i in range(left, first_index+1):
key *= nums[i]
self.res = max(self.res, mid//key)
key = 1
for i in range(end_index, right+1):
key *= nums[i]
self.res = max(self.res, mid//key)
else:
self.res = max(self.res, mid)
if len(nums) == 1: return nums[0] # 只有一个元素 ,特判
self.res = 0
i = 0
while i < len(nums) and nums[i] == 0: # 找第一个不为0的元素, 如 [0,0,0,0,1,2,3]
i += 1
if i == len(nums): return 0
j = i + 1
while j < len(nums):
if nums[j] == 0:
handle(i, j-1)
# print(i, j-1)
i = j
while i < len(nums) and nums[i] == 0: # 找下一个不为0的元素,因为可能存在好多0 如[1,0,0,0,0,2,3]
i += 1
j = i+1
else:
j += 1
if j == len(nums) and nums[j-1] != 0:
handle(i, j-1)
return self.res
方法二: DP - 时间复杂度 O ( n ) O(n) O(n)
class Solution:
def maxProduct(self, nums: List[int]) -> int:
max_num, min_num, res = nums[0], nums[0], nums[0]
for i in range(1, len(nums)):
if nums[i] < 0:
max_num, min_num = min_num, max_num
max_num = max(max_num*nums[i], nums[i])
min_num = min(min_num*nums[i], nums[i])
res = max(res, max_num)
return res