如何实现统计字符串内连续重复字符的规则压缩算法
字符串压缩题实现思路
不用纠结一开始就非要用map/filter/reduce这类高阶函数,先把核心逻辑拆明白,用最朴素的写法跑通,之后再考虑用高阶函数简化就行,硬套API反而容易把自己绕晕。
先把题目要求拆成3个必须实现的规则:
- 按顺序统计连续重复字符的出现次数
- 按「字符+连续出现次数」的格式拼接压缩结果
- 最终比较压缩串和原串长度,压缩串更长则直接返回原串
最容易上手的基础实现步骤
- 先处理边界情况:字符串长度小于等于2时直接返回原串即可——这种情况压缩后每个字符都会带个后缀1,长度一定比原串长,没必要走后续计算。
- 初始化3个核心变量:
- 存压缩片段的数组(用数组拼接比逐次拼字符串性能更好)
- 当前正在统计的字符,初始值设为字符串第一个字符
- 当前字符的连续出现计数,初始值设为1
- 从字符串第二个字符(索引为1)开始遍历:
- 如果当前遍历到的字符和正在统计的字符一致,计数加1
- 如果不一致,就把当前统计的字符和计数存入结果数组,再把正在统计的字符更新为当前遍历到的字符,计数重置为1
- 遍历结束后,一定要把最后一组统计的字符和计数存入结果数组——这是新手最容易漏的点,漏了会丢失字符串最后一段的压缩结果。
- 把结果数组拼接成完整压缩串,和原串比长度:压缩串更短就返回压缩串,否则返回原串。
对应JS实现代码:
function compress(str) { if (str.length <= 2) return str; const res = []; let currentChar = str[0]; let count = 1; for (let i = 1; i < str.length; i++) { if (str[i] === currentChar) { count++; } else { res.push(currentChar, count); currentChar = str[i]; count = 1; } } // 补上最后一组字符统计 res.push(currentChar, count); const compressedStr = res.join(''); return compressedStr.length < str.length ? compressedStr : str; } // 测试用例运行结果 compress("aaaaabbbbbbbbcd") // "a5b8c1d1" compress("abcaaaaaaaaaaaaaaaaaabbc") // "a1b1c1a18b2c1" compress("ab") // "ab"
用reduce的简化写法
等你把基础逻辑摸透了,完全可以用reduce改写,本质只是把计数和结果数组放到reduce的初始值里,核心逻辑和上面的写法没有区别:
function compressWithReduce(str) { if (str.length <= 2) return str; const compressed = str.split('').reduce((acc, char, idx, arr) => { acc.count++; if (char !== arr[idx + 1]) { acc.res.push(char, acc.count); acc.count = 0; } return acc; }, { res: [], count: 0 }).res.join(''); return compressed.length < str.length ? compressed : str; }
新手容易踩的坑
- 遍历结束忘记追加最后一组字符统计,导致结果丢失末尾片段
- 计数初始值设为0,导致第一个字符的统计值少1
- 拼接完压缩串直接返回,忘记做长度校验,过不了短串返回原内容的用例
- 一开始就硬套高阶函数,反而把简单的计数逻辑绕复杂
内容的提问来源于stack exchange,提问作者ofigensky
相关产品推荐
相关产品推荐

