如何高效求解字符串数组中指定长度的最频繁公共子串
原有代码问题梳理
- 子串统计索引错误:使用字符串遍历下标
j访问seq数组,二者长度无对应关系,会频繁获取到undefined,导致map统计完全异常 - 遍历逻辑错误:else分支额外执行
j++,会跳过部分子串采集,出现统计遗漏 - 缺少结果匹配逻辑:统计完成后没有从map中提取出现次数最高的子串,直接返回了初始空值
- 冗余判断:
array[i].includes(str)属于无效判断,从原字符串切片得到的符合长度要求的子串必然属于原字符串
实现方案
基础版本(统计子串总出现次数)
符合你给出的示例要求,子串在所有字符串中每出现一次就计数一次:
function commonSubstring(array, length) { const countMap = {}; // 边界情况直接返回 if (!array.length || length <= 0) return ''; // 遍历所有字符串提取子串统计 for (const str of array) { if (str.length < length) continue; // 遍历所有可能的切片起始位置 for (let i = 0; i <= str.length - length; i++) { const substr = str.slice(i, i + length); countMap[substr] = (countMap[substr] || 0) + 1; } } // 查找出现次数最高的子串 let maxCount = 0; let mostCommon = ''; for (const [substr, count] of Object.entries(countMap)) { if (count > maxCount) { maxCount = count; mostCommon = substr; } } return mostCommon; }
可选版本(统计子串出现在多少个不同字符串中)
如果需求是同一字符串内的相同子串只算一次,可以改用该实现,避免单个字符串中重复出现的子串拉高计数:
function commonSubstring(array, length) { const countMap = {}; if (!array.length || length <= 0) return ''; for (const str of array) { if (str.length < length) continue; // 单个字符串先去重再统计 const substrSet = new Set(); for (let i = 0; i <= str.length - length; i++) { substrSet.add(str.slice(i, i + length)); } substrSet.forEach(substr => { countMap[substr] = (countMap[substr] || 0) + 1; }) } let maxCount = 0; let mostCommon = ''; for (const [substr, count] of Object.entries(countMap)) { if (count > maxCount) { maxCount = count; mostCommon = substr; } } return mostCommon; }
测试验证
- 示例1调用:
commonSubstring(["abc", "usbc", "bcde"], 2),返回"bc",符合预期 - 示例2调用:
commonSubstring(["terrific", "specific"], 4),返回"ific",符合预期(注:你给出的示例2输入写法有误,数组元素的逗号是字符串内字符,应为两个独立字符串元素)
时间复杂度为O(N*M),其中N为输入数组长度,M为单个字符串平均长度,可满足绝大多数场景的性能要求。
内容的提问来源于stack exchange,提问作者MiniDracaena
相关产品推荐
相关产品推荐

