JavaScript实现限制字符串字符重复次数的函数及代码修复
现有代码的核心问题
- 逻辑设计完全偏离需求:当前实现会把字符串中所有同字符的位置无差别聚合成独立数组,先将原字符串打乱为无重复的字符顺序,再把裁剪后的同字符片段整体拼接到结果末尾。既没有保留原字符串的连续分段顺序,还会把跨分段的同字符合并统计总长度再裁剪,直接丢失本该保留的后置同字符——比如处理"aadaa"时,所有4个a被合并统计,按r=1只留1个a,加上原去重串裁剪后剩下的字符,最终才会得到错误的"ad",而非预期的"ada",更无法匹配"aassaa"输入r=1时输出"asa"的要求。
- 性能效率极低:每遍历一个字符就对全字符串执行一次
filter匹配同字符,整体时间复杂度为O(n²),字符串长度稍大就会出现明显卡顿。 - 实现存在隐患:
el.splice(0, true)这种依赖隐式类型转换传删除参数的写法可读性极差,后续维护成本很高。
正确实现方案
你要的效果本质是顺着原字符串顺序,对每一段连续重复的同字符,最多保留r个字符,不需要做跨分段的字符聚合统计:
- 先做入参兼容:数组类型入参直接拼接为字符串,非字符串类型直接返回
- 流式遍历字符串每一个字符,不需要提前把所有同字符聚组
- 遍历过程中只需记录两个值:当前连续重复段的字符、该段已经保留的字符数量
- 遇到新的连续字符就重置段记录和保留计数;当前段的保留数量没达到r上限时,就把字符加入最终结果
参考代码
function unique(s, r) { // 入参兼容处理 if (Array.isArray(s)) s = s.join(""); if (typeof s !== "string") return; const result = []; let currentSegmentChar = ""; // 记录当前连续段的字符 let keptCount = 0; // 当前连续段已保留的字符数 for (const char of s) { // 遇到新字符,重置连续段状态 if (char !== currentSegmentChar) { currentSegmentChar = char; keptCount = 0; } // 当前段未达保留上限,就将字符加入结果 if (keptCount < r) { result.push(char); keptCount++; } } return result.join(""); }
用例验证
// 匹配核心需求 console.log(unique("aassaa", 1)); // 输出 "asa",符合预期 console.log(unique("aadaa", 1)); // 输出 "ada",解决原有bug // 其余测试场景 console.log(unique("aaa", 1)); // 输出 "a" console.log(unique("aaa", 2)); // 输出 "aa" console.log(unique(["a","a","b","a","a","a"], 2)); // 输出 "aabaa" console.log(unique(["a","a","b","a","a","a"], 1)); // 输出 "aba"
说明:你之前写的测试用例注释里的输出结果,是原有bug代码的实际运行结果,不是功能预期。参考代码严格按照"aassaa输入r=1输出asa"的规则实现,全程保留原字符串的连续分段顺序,跨分段的同字符不会被合并统计。
内容的提问来源于stack exchange,提问作者Lehmann
相关产品推荐
相关产品推荐

