
本文介绍如何通过集合去重与函数式编程方法,高效提取字符串数组与目标字符串之间的公共字母,彻底解决嵌套 for 循环引发的重复匹配问题。
本文介绍如何通过集合去重与函数式编程方法,高效提取字符串数组与目标字符串之间的公共字母,彻底解决嵌套 for 循环引发的重复匹配问题。
在字符串比对场景中,使用双重 for 循环逐字符遍历虽直观,但极易因重复字符(如 "Apple" 中的 'p' 或 'e')导致同一字母被多次匹配和输出——正如原代码中 "aaa" 被错误映射为 "aaaaaa"。根本原因在于:未对源字符串或目标字符串中的字母做去重处理,且循环逻辑未区分“是否存在”与“出现几次”。
要精准获取「公共字母集合」(即交集),关键在于将比较维度从「字符频次」降维到「字符存在性」。推荐采用 Set 数据结构预处理双方字母,因其天然具备唯一性和 O(1) 查找效率。
以下是优化后的完整实现:
const fruits = ["Banana", "Orange", "Apple", "Mango", "Apple"];
const myString = "apple";
const findCommonLetters = (array, string) => {
// 步骤1:构建目标字符串的小写唯一字母集合
const uniqueStringLetters = new Set(string.toLowerCase());
// 步骤2:对数组中每个单词执行:
// • 转小写 → 去重 → 筛选存在于目标集合中的字母 → 合并为字符串
return array.map(fruit =>
[...new Set(fruit.toLowerCase())]
.filter(letter => uniqueStringLetters.has(letter))
.join('')
);
};
console.log(findCommonLetters(fruits, myString));
// 输出: ['aple', 'oe', 'aple', 'ae', 'aple']
// 解释:Apple → {a,p,l,e} ∩ {a,p,p,l,e} → "aple"(顺序依原词首次出现顺序)✅ 优势说明:
-
new Set(fruit.toLowerCase())消除单词内重复字母(如"Apple"→{'a','p','l','e'}); -
new Set(string.toLowerCase())确保目标字符串仅作为“字母池”,不关心重复; -
filter(...has(letter))实现高效交集判断,避免 N² 复杂度下的冗余匹配。
⚠️ 注意事项:
- 若需保持字母在原单词中的首次出现顺序(如示例输出
"aple"而非"aelpp"),应使用扩展运算符[...Set]而非Array.from(Set).sort(); - 若业务要求统计最小共现频次(如
"aabb"与"abbb"公共字母为"ab",各取 min(2,1)=1 个),则需改用Map记录频次,本方案不适用; - 当前逻辑区分大小写:统一转小写后比较,如需保留原始大小写形态,应在去重前记录映射关系。
该方案以语义清晰、性能稳定、无副作用的特点,成为字符串字母交集计算的标准实践。

















