题目描述
给你一个整数数组 nums ,请你求出乘积为正数的最长子数组的长度。 一个数组的子数组是由原数组中零个或者更多个连续数字组成的数组。 请你返回乘积为正数的最长子数组长度。
注意,我们不能把 0 也包括到子数组中,因为这样乘积为 0 ,不是正数。
示例 :
输入:nums = [0,1,-2,-3,-4]
输出:3
解释:最长乘积为正数的子数组为 [1,-2,-3] ,乘积为 6 。
动态规划思路
1. 定义状态
首先,我们需要定义状态来表示问题的子问题。在这个问题中,我们关心的是以某个元素结尾的子数组的最长乘积为正数的长度。但是,由于乘积可能涉及正负数的相乘,我们还需要额外跟踪以某个元素结尾的子数组的最长乘积为负数的长度。
因此,我们定义两个状态:
pos[i]
:以nums[i]
结尾的最长乘积为正数的子数组的长度。neg[i]
:以nums[i]
结尾的最长乘积为负数的子数组的长度。
注意,我们并不直接定义一个状态来表示“最长乘积为正数的子数组的长度”,因为那样会很难处理跨越多个元素的乘积变化(特别是涉及到负数时)。相反,我们通过跟踪以每个元素结尾的乘积长度,来间接找到全局的最长乘积为正数的子数组长度。
2. 初始化状态
在遍历数组之前,我们需要对状态进行初始化。特别是,我们需要考虑数组的第一个元素 nums[0]
:
- 如果
nums[0] > 0
,则pos[0] = 1
,neg[0] = 0
(因为没有以它为结尾的负数乘积子数组)。 - 如果
nums[0] < 0
,则pos[0] = 0
,neg[0] = 1
(因为它本身就是一个负数乘积子数组)。 - 如果
nums[0] == 0
,则pos[0] = 0
,neg[0] = 0
(因为它不贡献给任何乘积子数组)。
但是,为了简化代码,我们通常会省略对 nums[0] == 0
的特殊处理,因为当遇到0时,pos
和 neg
自然会因为后续的计算而变为0(或者保持为0,如果它们之前已经是0的话)。
3. 状态转移方程
接下来,我们需要根据当前元素 nums[i]
和前一个状态 pos[i-1]
、neg[i-1]
来更新 pos[i]
和 neg[i]
。
- 如果
nums[i] > 0
,则当前元素可以扩展之前的正数乘积子数组,或者开始一个新的正数乘积子数组(如果之前是负数乘积子数组的话)。因此,pos[i] = pos[i-1] + 1
,并且如果之前有负数乘积子数组(neg[i-1] > 0
),则neg[i] = neg[i-1] + 1
(表示乘以当前正数后变成负数乘积),如果之前没有有负数乘积子数组(neg[i-1] == 0
),则neg[i] = 0 。
- 如果
nums[i] < 0
,则情况相反:它可以扩展之前的负数乘积子数组,或者如果之前是正数乘积子数组的话,开始一个新的负数乘积子数组。因此,neg[i] = pos[i-1] + 1
(如果之前有正数乘积则扩展,否则为1),并且pos[i] = (neg[i-1] > 0) ? neg[i-1] + 1 : 0
(如果之前有负数乘积则扩展为正数乘积,否则为0)。 - 如果
nums[i] == 0
,则pos[i] = 0
和neg[i] = 0
,因为0不贡献给任何乘积子数组。但在实际实现中,我们通常会省略这个判断,因为当nums[i]
为0时,pos[i]
和neg[i]
的计算会自动导致它们为0(或者保持为0)。
4. 边界条件和特殊情况
- 当数组为空时,最长乘积为正数的子数组长度为0。
- 在遍历过程中,我们需要同时跟踪并更新全局的最长乘积为正数的子数组长度。
5. 最终结果
遍历完整个数组后,全局的最长乘积为正数的子数组长度就保存在我们跟踪的变量中(或者在遍历过程中不断更新)。
代码示例
class Solution {
public:
int getMaxLen(vector<int>& nums) {
int n = nums.size();
vector<int> f(n, 0); // f(i)以i为结尾的乘积为正数的最长子数组长度
vector<int> g(n, 0); // g(i)以i为结尾的乘积为负数的最长子数组长度
if (nums[0] > 0) {
f[0] = 1;
g[0] = 0;
} else if (nums[0] < 0) {
f[0] = 0;
g[0] = 1;
}
int ret = f[0];
for (int i = 1; i < n; i++) {
if (nums[i] > 0) {
f[i] = f[i - 1] + 1;
g[i] = g[i - 1] == 0 ? 0 : g[i - 1] + 1;
} else if (nums[i] < 0) {
f[i] = g[i - 1] == 0 ? 0 : g[i - 1] + 1;
g[i] = f[i - 1] + 1;
}
ret = max(ret, f[i]);
}
return ret;
}
};