一、题目描述
给定一个数组,我们称其中连续的元素为连续子序列,称这些元素的和为连续子序列的和。
数组中可能存在几组连续子序列,组内的连续子序列互不相交且有相同的和。
求一组连续子序列,组内子序列的数目最多。输出这个数目。
二、输入输出描述
输入描述
- 第一行:数组长度 N,1 <= N <= 10^3;
- 第二行:N 个用空格分开的整数 Ci,-10^5 <= Ci <= 10^5。
输出描述
- 一个整数 M,表示满足要求的最多的组内子序列的数目。
三、示例
|----|-------------------------------------------|
| 输入 | 10 8 8 9 1 9 6 3 9 1 0 |
| 输出 | 4 |
| 说明 | 四个子序列的第一个元素和最后一个元素的下标分别为: 2 2 4 4 5 6 7 7 |
|----|---------------------------------------|
| 输入 | 10 -1 0 4 -3 6 5 -6 5 -7 -3 |
| 输出 | 3 |
| 说明 | 三个子序列的第一个元素和最后一个元素的下标分别为: 3 3 5 8 9 9 |
四、解题思路
1. 核心思想
暴力枚举所有可能的子数组和 + 贪心选取:
- 枚举每一个可能的子数组和 target
- 对每个 target,用贪心算法 从左到右选出最多的不重叠子数组
- 遍历所有 target 后,保留最大数量
2. 问题本质分析
这是一个最优选择问题:
- 条件:选出若干不重叠 子数组,所有子数组和必须相同
- 目标:子数组数量尽可能多 本质是:尝试所有可能的和 → 对每个和计算最多能选多少个 → 取最大值。
3. 核心逻辑
- 枚举目标和 target:从 -1000 万 到 1000 万,覆盖所有可能出现的子数组和
- 贪心查找 :对每个 target,从左到右遍历 ,一旦找到和为 target 的子数组就立刻选中 ,然后从下一个位置继续找,保证不重叠 且数量最多
- 记录最大值 :遍历所有 target,保留能选出的最大子数组数量
4. 步骤拆解
-
输入读取
- 读取数组长度 n 和数组元素
-
枚举目标和
- 遍历所有可能的子数组和 target(-1000 万~1000 万)
-
贪心计算当前 target 能选多少个
- 从左到右找和为 target 的子数组
- 找到就计数,且跳过已选区域保证不重叠
- 找不到就后移一位继续
-
更新最优解
- 记录所有 target 中能选出的最大数量
-
输出结果
- 输出最大数量
五、代码实现
java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();
}
int maxCount = 0;
// 枚举所有可能的区间和
for (int target = -10000000; target <= 10000000; target++) {
int count = 0;
int pos = 0;
// 贪心:从左到右选不重叠的和为 target 的子数组
while (pos < n) {
int sum = 0;
boolean found = false;
for (int j = pos; j < n; j++) {
sum += a[j];
if (sum == target) {
count++;
pos = j + 1;
found = true;
break;
}
}
if (!found) {
pos++;
}
}
if (count > maxCount) {
maxCount = count;
}
}
System.out.println(maxCount);
}
}