本文介绍一种基于 reduce 和对象集合的高效方法,用于在数组中一次性找出所有以指定起始字符和结束字符构成的合法索引对(如 'a'→'c'),避免分别收集再嵌套遍历,时间复杂度更优且逻辑清晰。
本文介绍一种基于 reduce 和对象集合的高效方法,用于在数组中一次性找出所有以指定起始字符和结束字符构成的合法索引对(如 'a'→'c'),避免分别收集再嵌套遍历,时间复杂度更优且逻辑清晰。
在实际开发中,我们常需从数组中提取具有语义关系的元素位置,例如“第一个出现的 'a' 之后、最近的一个 'c'”构成一对索引。但注意:原问题中示例 [0, 2] 和 [5, 6] 并非任意 'a' 后接任意 'c',而是隐含顺序匹配逻辑——即每个 'a' 尽量与它之后首次出现的 'c' 配对(类似“贪心左对齐”),且不重叠、不回溯。然而,原始答案提供的代码实际实现的是按出现顺序分组配对:将 'a' 和 'c' 视为同一“事件组”的两个成员,依次填充到不同对象中,最终形成 [a₀, c₀]、[a₁, c₁] 等一一对应关系(即索引 0 与 2 配对,5 与 6 配对),这正符合题干示例的预期。
以下是优化后的专业实现方案:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
✅ 推荐解法:单次遍历 + 分组映射(稳定、可读、可扩展)
function findAllIndexPairs(arr, startChar, endChar) {
const chars = new Set([startChar, endChar]);
const groups = []; // 存储多个 { [startChar]: i, [endChar]: j } 对象
arr.reduce((acc, char, index) => {
if (!chars.has(char)) return acc;
// 尝试向现有组填充:优先填入缺失的字符
for (const group of acc) {
if (char in group) continue; // 当前组已有该字符,跳过
group[char] = index;
return acc; // 成功填充,立即返回
}
// 所有组都不含该字符 → 新建一组
acc.push({ [char]: index });
return acc;
}, groups);
// 过滤出完整包含 startChar 和 endChar 的组,并标准化为 [startIdx, endIdx] 数组
return groups
.filter(group => startChar in group && endChar in group)
.map(group => [
group[startChar],
group[endChar]
])
.sort((a, b) => a[0] - b[0]); // 按起始索引升序排列,保证结果可预测
}
// 示例调用
const arr = ['a', 'b', 'c', 'd', 'e', 'a', 'c'];
console.log(findAllIndexPairs(arr, 'a', 'c'));
// 输出: [[0, 2], [5, 6]]
⚠️ 注意事项与边界说明
- 字符顺序无关性:该算法不强制 startChar 必须出现在 endChar 之前;若数组中先出现 'c' 再出现 'a',仍会生成 [cIndex, aIndex] 对(此时可加 if (group[startChar]
- 严格一一配对:每个 'a' 和 'c' 最多参与一次配对(首个未被占用的匹配项),符合“贪心分组”语义。
- 性能优势:仅遍历数组一次,时间复杂度 O(n),空间复杂度 O(k)(k 为配对组数),优于双重循环的 O(n²)。
- 扩展性:轻松支持更多字符(如三元组 'a'→'b'→'c'),只需扩展 Set 并调整 filter 条件。
? 替代思路(如需“首个后续匹配”)
若需求实为“对每个 'a',找它之后**第一个 'c'”,则应使用双指针或预处理 nextOccurrence 映射:
// 预计算每个位置后最近的 'c' 索引(向右扫描)
const nextC = new Array(arr.length).fill(-1);
let lastC = -1;
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i] === 'c') lastC = i;
if (lastC !== -1) nextC[i] = lastC;
}
// 然后遍历找 'a':arr[i]==='a' && nextC[i]!==-1 ? [i, nextC[i]] : null
综上,针对题干示例与目标,分组映射法是最简洁、健壮且符合直觉的解决方案,兼顾性能与可维护性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










