leetcode1567. 乘积为正数的最长子数组长度
给你一个整数数组 nums
,请你求出乘积为正数的最长子数组的长度。
一个数组的子数组是由原数组中零个或者更多个连续数字组成的数组。
请你返回乘积为正数的最长子数组长度。
示例 1:
输入:nums = [1,-2,-3,4]
输出:4
解释:数组本身乘积就是正数,值为 24 。
示例 2:
输入:nums = [0,1,-2,-3,-4]
输出:3
解释:最长乘积为正数的子数组为 [1,-2,-3] ,乘积为 6 。
注意,我们不能把 0 也包括到子数组中,因为这样乘积为 0 ,不是正数。
示例 3:
输入:nums = [-1,-2,-3,0,1]
输出:2
解释:乘积为正数的最长子数组是 [-1,-2] 或者 [-2,-3] 。
示例 4:
输入:nums = [-1,2]
输出:1
示例 5:
输入:nums = [1,2,3,5,-6,4,0,10]
输出:4
提示:
1 <= nums.length <= 10^5
-10^9 <= nums[i] <= 10^9
方法:动态规划
思路:
本题使用动态规划的方法。
为了忽略边界条件的影响,我们使用dp[i][0]
表示以nums[i-1]为结尾的,最长乘积为正数的子数组的长度;dp[i][1]
表示以nums[i-1]为结尾的,最长乘积为负数的子数组的长度。
初始化dp都为0,dp数组的长度为n+1。
然后我们遍历nums数组来填写dp数组,对于nums[i],以它结尾的正负子数组长度对应为dp[i+1],nums[i]可能有3种情况:
- nums[i]>0,此时
dp[i+1][0] = dp[i][0] + 1
,即正子数组变长+1;对于负子数组,如果前面负子数组存在,即dp[i][1]!=0
,那么加上nums[i]仍为负,负子数组变长+1;即dp[i+1][1] = dp[i][1] + 1
,如果前面负子数组不存在,则dp[i+1][1] = 0
。 - nums[i]<0,此时
dp[i+1][1] = dp[i][0] + 1
,即前面的正子数组×这个数之后,变为负子数组,且长度+1,这里不用考虑前面正子数组不存在的情况,因为不存在也是0+1=1。对于正子数组,与上面类似,如果前面负子数组存在,那么加上这个数,负负得正,变为正子数组,即dp[i+1][0] = dp[i][1] + 1
,如果不存在,那么为0。 - nums[i]=0,所有子数组乘积都变为0,因此
dp[i+1]=[0,0]
。
遍历的过程中,我们使用一个变量res来不断维护最大的dp[i] [0],最后返回即可。
- 只遍历了一次,时间复杂度为O(N)。
- 空间复杂度为O(N),因为每个状态只与它前面的状态有关,因此不必使用两个数组,只使用两个变量可将空间复杂度优化到O(1)。
代码:
Python3:
class Solution:
def getMaxLen(self, nums: List[int]) -> int:
n = len(nums)
# dp[i][0]表示以nums[i-1]结尾的,最长乘积为正数的子数组长度
# dp[i][1]表示以nums[i-1]结尾的,最长乘积为负数的子数组长度
# 这里以nums[i-1]结尾,是为了不需要考虑边界条件
# 最后的结果应