题解 | #乘积为正数的最长连续子数组#
乘积为正数的最长连续子数组
https://www.nowcoder.com/practice/0112b9b5a09048d89309f55ea666db91?tpId=230&tqId=2378149&ru=/exam/oj&qru=/ta/dynamic-programming/question-ranking&sourceUrl=%2Fexam%2Foj
遍历到数组元素时,分别考虑3种情况:正数、0、负数
- 正数,没什么好说的,dp[i] = dp[i-1] + 1
- 0,直接重置 dp 数组和 negativeCnt,dp[i] = 0,negativeCnt = 0 (记录负数的个数)
- 负数,首先将负数个数加1,然后判断负数个数是偶数还是奇数
- 奇数,首先当前 dp 值置为 0 —— dp[i] = 0,然后记录此时 dp[i-1] 的值 —— int pre = dp[i - 1]
- 偶数,则需要加上上一个负数前面的最长连续子数组长度和两个负数的个数 —— dp[i] = dp[i-1] + pre + 2
定义初始状态:根据数组第一个元素 nums[0] 分别判断 dp[0] 和 negativeCnt
- dp[0] = nums[0] > 0 ? 1 : 0
- negativeCnt = nums[0] < 0 ? 1 : 0
最后返回 dp 数组中的最大值(ps:dp[i] 表示以下标 nums[i] 结尾的子数组,其乘积为正数的长度)
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int[] nums = new int[n]; for (int i = 0; i < nums.length; i++) { nums[i] = in.nextInt(); } System.out.println(maxProduct(nums)); } public static int maxProduct(int[] nums) { int result = 0; int pre = 0; // 记录奇数个负数时dp[i-1]的值 int[] dp = new int[nums.length]; dp[0] = nums[0] > 0 ? 1 : 0; int negativeCount = nums[0] < 0 ? 1 : 0; // 记录负数的个数 for (int i = 1; i < nums.length; i++) { if (nums[i] > 0) { dp[i] = dp[i - 1] + 1; } else { // nums[i] <= 0 if (nums[i] == 0) { negativeCount = 0; dp[i] = 0; } else { // nums[i] < 0 negativeCount++; if ( negativeCount % 2 == 0) { dp[i] = dp[i - 1] + pre + 2; // 偶数个负数时,加上第奇数个负数和当前负数,故加2 } else { dp[i] = 0; pre = dp[i - 1]; // 记录奇数个负数时dp[i-1]的值 } } } result = Math.max(result, dp[i]); } return result; } }