1567-乘积为正数的最长子数组长度

Raphael Liu Lv10

给你一个整数数组 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 <= nums.length <= 10^5
  • -10^9 <= nums[i] <= 10^9

方法一:动态规划

可以使用动态规划得到乘积为正数的最长子数组长度。定义两个数组 positive 和 negative,其中 positive}[i] 表示以下标 i 结尾的乘积为正数的最长子数组长度,negative}[i] 表示乘积为负数的最长子数组长度。

当 i=0 时,以下标 i 结尾的子数组的长度为 1,因此当 nums}[0]>0 时 positive}[0]=1,当 nums}[0]<0 时 negative}[0]=1。

当 i>1 时,根据 nums}[i] 的值计算 positive}[i] 和 negative}[i] 的值。

  • 当 nums}[i]>0 时,之前的乘积乘以 nums}[i] 不会改变乘积的正负性。

    positive}[i] 的计算为:

    \textit{positive}[i]=\textit{positive}[i-1]+1

    negative}[i] 的计算为:

    \textit{negative}[i]=\begin{cases}
    \textit{negative}[i-1]+1, & \textit{negative}[i-1]>0 \
    0, & \textit{negative}[i-1] = 0
    \end{cases}

    这是因为当 negative}[i-1]=0 时,negative}[i] 本身无法形成一个乘积为正数的子数组,所以要特殊判断。

  • 当 nums}[i]<0 时,之前的乘积乘以 nums}[i] 会改变乘积的正负性。

    positive}[i] 的计算为:

    \textit{positive}[i]=\begin{cases}
    \textit{negative}[i-1]+1, & \textit{negative}[i-1]>0 \
    0, & \textit{negative}[i-1] = 0
    \end{cases}

    这是因为当 negative}[i-1]=0 时,positive}[i] 本身无法形成一个乘积为负数的子数组,所以要特殊判断。

    negative}[i] 的计算为:

    \textit{negative}[i]=\textit{positive}[i-1]+1

  • 当 nums}[i]=0 时,以下标 i 结尾的子数组的元素乘积一定为 0,因此有 positive}[i]=0 和 negative}[i]=0。

在计算 positive 和 negative 两个数组的过程中维护乘积为正数的最长子数组长度,当遍历结束时,即可得到最长子数组长度。

[sol11-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public int getMaxLen(int[] nums) {
int length = nums.length;
int[] positive = new int[length];
int[] negative = new int[length];
if (nums[0] > 0) {
positive[0] = 1;
} else if (nums[0] < 0) {
negative[0] = 1;
}
int maxLength = positive[0];
for (int i = 1; i < length; i++) {
if (nums[i] > 0) {
positive[i] = positive[i - 1] + 1;
negative[i] = negative[i - 1] > 0 ? negative[i - 1] + 1 : 0;
} else if (nums[i] < 0) {
positive[i] = negative[i - 1] > 0 ? negative[i - 1] + 1 : 0;
negative[i] = positive[i - 1] + 1;
} else {
positive[i] = 0;
negative[i] = 0;
}
maxLength = Math.max(maxLength, positive[i]);
}
return maxLength;
}
}
[sol11-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
int getMaxLen(vector<int>& nums) {
int length = nums.size();
vector<int> positive(length), negative(length);
if (nums[0] > 0) {
positive[0] = 1;
}
else if (nums[0] < 0) {
negative[0] = 1;
}
int maxLength = positive[0];
for (int i = 1; i < length; ++i) {
if (nums[i] > 0) {
positive[i] = positive[i - 1] + 1;
negative[i] = (negative[i - 1] > 0 ? negative[i - 1] + 1 : 0);
}
else if (nums[i] < 0) {
positive[i] = (negative[i - 1] > 0 ? negative[i - 1] + 1 : 0);
negative[i] = positive[i - 1] + 1;
}
else {
positive[i] = 0;
negative[i] = 0;
}
maxLength = max(maxLength, positive[i]);
}
return maxLength;
}
};
[sol11-Python3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution:
def getMaxLen(self, nums: List[int]) -> int:
length = len(nums)
positive, negative = [0] * length, [0] * length
if nums[0] > 0:
positive[0] = 1
elif nums[0] < 0:
negative[0] = 1

maxLength = positive[0]
for i in range(1, length):
if nums[i] > 0:
positive[i] = positive[i - 1] + 1
negative[i] = (negative[i - 1] + 1 if negative[i - 1] > 0 else 0)
elif nums[i] < 0:
positive[i] = (negative[i - 1] + 1 if negative[i - 1] > 0 else 0)
negative[i] = positive[i - 1] + 1
else:
positive[i] = negative[i] = 0
maxLength = max(maxLength, positive[i])

return maxLength

注意到 positive}[i] 和 negative}[i] 的值只与 positive}[i-1] 和 negative}[i-1] 有关,因此可以使用滚动数组优化空间。

[sol12-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public int getMaxLen(int[] nums) {
int length = nums.length;
int positive = nums[0] > 0 ? 1 : 0;
int negative = nums[0] < 0 ? 1 : 0;
int maxLength = positive;
for (int i = 1; i < length; i++) {
if (nums[i] > 0) {
positive++;
negative = negative > 0 ? negative + 1 : 0;
} else if (nums[i] < 0) {
int newPositive = negative > 0 ? negative + 1 : 0;
int newNegative = positive + 1;
positive = newPositive;
negative = newNegative;
} else {
positive = 0;
negative = 0;
}
maxLength = Math.max(maxLength, positive);
}
return maxLength;
}
}
[sol12-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
int getMaxLen(vector<int>& nums) {
int length = nums.size();
int positive = (nums[0] > 0);
int negative = (nums[0] < 0);
int maxLength = positive;
for (int i = 1; i < length; ++i) {
if (nums[i] > 0) {
++positive;
negative = (negative > 0 ? negative + 1 : 0);
}
else if (nums[i] < 0) {
int newPositive = negative > 0 ? negative + 1 : 0;
int newNegative = positive + 1;
tie(positive, negative) = {newPositive, newNegative};
}
else {
positive = negative = 0;
}
maxLength = max(maxLength, positive);
}
return maxLength;
}
};
[sol12-Python3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution:
def getMaxLen(self, nums: List[int]) -> int:
length = len(nums)
positive, negative = int(nums[0] > 0), int(nums[0] < 0)
maxLength = positive

for i in range(1, length):
if nums[i] > 0:
positive += 1
negative = (negative + 1 if negative > 0 else 0)
elif nums[i] < 0:
newPositive = (negative + 1 if negative > 0 else 0)
newNegative = positive + 1
positive, negative = newPositive, newNegative
else:
positive = negative = 0
maxLength = max(maxLength, positive)

return maxLength

复杂度分析

  • 时间复杂度:O(n),其中 n 是数组的长度。遍历数组一次,在遍历过程中维护最长子数组长度,对于数组中的每个元素的时间复杂度都是 O(1),因此总时间复杂度是 O(n)。

  • 空间复杂度:O(1)。通过滚动数组实现,只需要使用常数的额外空间。

 Comments
On this page
1567-乘积为正数的最长子数组长度