题目链接
Leetcode.1567 乘积为正数的最长子数组长度 Rating : 1710
题目描述
给你一个整数数组 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] 。
提示:
- 1 < = n u m s . l e n g t h < = 1 0 5 1 <= nums.length <= 10^5 1<=nums.length<=105
- − 1 0 9 < = n u m s [ i ] < = 1 0 9 -10^9 <= nums[i] <= 10^9 −109<=nums[i]<=109
分析:
首先,要想子数组的乘积为正数,那么子数组里面一定不包含 0
,而且负数的个数为偶数。
- 我们用
positive
记录 正数 的个数 - 我们用
negative
记录 负数 的个数 - 我们用
neg_pos
(初始为-1
)记录 第一个负数出现的位置
在遍历的过程中,会遇到以下三种情况:
nums[i] > 0
,遇到正数positive
就+1
。nums[i] < 0
,遇到负数negative
就+1
,如果此时neg_pos == -1
,说明nums[i]
是目前遇到的第一个负数,更新neg_pos = i
。nums[i] == 0
,遇到0
,positve
重置为0
,negative
重置为0
,neg_pos
重置为-1
。相当于0
把每一个合法的子数组都截开了。
在更新答案ans
的时候:
- 如果当前子数组中的负数个数是偶数个,即
negative % 2 == 0
,ans = max(ans , positive + negative)
,即当前整个子数组乘积都是正数。 - 如果当前子数组中的负数个数是奇数个,即
negative % 2 != 0
,那么当前子数组就需要剔除一个负数来保证整个子数组乘积为正数,我们就选择剔除 第一个出现的负数。即ans = max(ans , i - neg_pos)
,剔除了 下标为neg_pos
的负数。
时间复杂度: O ( n ) O(n) O(n)
C++代码:
class Solution {
public:
int getMaxLen(vector<int>& nums) {
int positive = 0,negative = 0,neg_pos = -1;
int ans = 0;
int n = nums.size();
for(int i = 0;i < n;i++){
int x = nums[i];
if(x > 0) positive++;
else if(x < 0){
negative++;
if(neg_pos == -1) neg_pos = i;
}
else{
positive = 0;
negative = 0;
neg_pos = -1;
}
if(negative % 2 == 0) ans = max(ans,negative + positive);
else ans = max(ans,i - neg_pos);
}
return ans;
}
};
Java代码:
class Solution {
public int getMaxLen(int[] nums) {
int positive = 0;
int negative = 0;
int neg_pos = -1;
int n = nums.length;
int ans = 0;
for(int i = 0;i < n;i++){
int x = nums[i];
if(x > 0) positive++;
else if(x < 0){
negative++;
if(neg_pos == -1) neg_pos = i;
}
else{
positive = 0;
negative = 0;
neg_pos = -1;
}
if(negative % 2 == 0) ans = Math.max(ans,negative + positive);
else ans = Math.max(ans,i - neg_pos);
}
return ans;
}
}