
本文介绍一种基于贪心策略的数组分组方法:遍历原数组,动态累积求和,每当加入下一个数会导致总和超过20时,就将当前累积组存入结果,并以该数为新组起点;最终得到若干子数组,每组元素之和 ≤ 20(严格小于或可等于,依需求而定)。
本文介绍一种基于贪心策略的数组分组方法:遍历原数组,动态累积求和,每当加入下一个数会导致总和超过20时,就将当前累积组存入结果,并以该数为新组起点;最终得到若干子数组,每组元素之和 ≤ 20(严格小于或可等于,依需求而定)。
在处理文件批量上传、日志切片或资源打包等场景中,常需将一组带“权重”(如文件大小,单位 MB)的项,划分为若干连续子序列,使得每个子序列的权重总和不超过指定阈值(如 20 MB)。这并非经典的子集和(NP-hard)问题,而是一个顺序约束下的贪心分组问题——必须保持原始顺序,且每组尽可能多地包含后续元素,只要不突破上限。
核心逻辑是:从左到右扫描,维护一个当前组(currentGroup)和其累加和(currentSum)。对每个新元素 v:
- 若
currentSum + v ,则将其加入当前组,更新 <code>currentSum; - 否则,将当前组推入结果数组,重置为
[v]和v,继续。
以下为清晰、可读性强的递归实现(ES6+):
const groupBySumThreshold = (arr, threshold = 20, index = 0, currentGroup = [], currentSum = 0, result = []) => {
// 基础情况:遍历完成
if (index >= arr.length) {
if (currentGroup.length > 0) result.push(currentGroup);
return result;
}
const v = arr[index];
// 判断是否能将当前元素加入已有组
if (currentSum + v <= threshold) {
return groupBySumThreshold(
arr,
threshold,
index + 1,
[...currentGroup, v],
currentSum + v,
result
);
} else {
// 超限 → 封装当前组,开启新组
result.push(currentGroup);
return groupBySumThreshold(
arr,
threshold,
index + 1,
[v],
v,
result
);
}
};
// 示例使用
const data = [3, 8, 9, 2, 7, 5, 6, 5, 3, 11, 9, 17, 6, 5, 8, 4, 2, 7, 9, 12, 5, 16, 4];
console.log(groupBySumThreshold(data));
// 输出示例:[[3,8,9],[2,7,5,6],[5,3,11],[9],[17],[6,5,8],[4,2,7,9],[12,5],[16,4]]⚠️ 注意事项:
- 该递归版本为尾递归友好设计,但 JavaScript 引擎默认不优化尾递归,超长数组可能导致栈溢出;生产环境建议改用迭代写法(
for循环)以保障稳定性; -
threshold支持动态传入,便于适配不同限制(如 15MB、25MB); - 分组严格保持原始顺序,不重排、不跳过元素;
- 每组和 ≤ threshold(含等于),若需严格
,仅需将条件改为 <code>currentSum + v ; - 空数组输入会返回空结果,单元素超限(如
[25])将生成[[25]]—— 即允许单个超限元素独立成组(符合“不跳过”要求)。
总结:本方案以简洁递归封装贪心逻辑,兼顾可读性与实用性。它不是暴力搜索所有组合,而是在线式(online)决策,时间复杂度 O(n),空间复杂度 O(n)(结果存储),是处理有序资源打包任务的高效实践方案。

















