字符串在算法面试中,单独考察的机会并不多,同样倾向于和一些经典算法(后面会讲的)结合来体现区分度。步子不能跨太大,不然容易扯着x。本节我们照样是先解决只需要数据结构知识做基础就可以解决的字符串问题。
在讲题之前,我首先要给大家点拨两个字符串相关的“基本算法技能”。这两个技能偶尔也会单独命题,但整体来看在综合性题目中的考察频率较高,需要大家着重熟悉、反复练习和记忆,确保真正做题时万无一失。
# 基本算法技能
⚡ 30 秒速记
- JavaScript 字符串不可变,所谓原地交换通常要先转字符数组,完成后再
join('') - 字符串题先确认比较单位是 UTF-16 code unit、Unicode code point 还是用户看到的字素簇,emoji 可能占多个 code unit
- 反转、回文常用左右指针把额外空间降为
O(1)(对字符数组而言),并把边界写成left < right
做字符串算法前,先要明确题目中的“字符”和“相等”按什么口径计算,再选择双指针、计数或滑动窗口。 只处理英文小写字母时按索引访问通常够用,但遇到 emoji、组合音标或多语言文本,就要区分 UTF-16 code unit、Unicode 码点和字素簇。反转或回文判断常用左右指针;由于 JavaScript 字符串不可变,需要修改时通常先转成字符数组,处理后再 join('')。空串、单字符、重复字符和超长输入也都应该覆盖。
字符串算法的第一步不是立刻写循环,而是定义“字符”和“相等”。只处理英文小写字母时,按索引读取通常足够;一旦输入包含 emoji、组合音标或多语言文本,就要区分 UTF-16 code unit、Unicode code point 与用户看到的字素簇。这个口径会直接决定长度、切分、反转和回文判断是否正确。
确定字符语义后,再根据访问模式选工具:两端向中间收缩用双指针,统计出现次数用 Map,连续区间约束用滑动窗口,复杂模式匹配则考虑状态机或动态规划。每个方案都要补空串、单字符、重复字符和超长输入,不能只验证 ASCII 样例。
💬 面试官追问
-
用户资料页限制昵称最多 10 个“字符”,但
'😀'.length得到2;产品、前端和后端在评审时必须先统一什么口径?必须先明确“字符”指
UTF-16 code unit、Unicodecodepoint,还是用户看到的字素簇。JavaScript的length按codeunit计数,Array.from()按codepoint拆分;面向视觉字符的限制通常还需Intl.Segmenter。 -
搜索框只处理英文小写字母,候选人仍为每次输入建立复杂分词对象;你会如何权衡正确性与实现成本?
若输入契约确实限定为英文小写字母,按索引读取已经能满足字符语义,没有必要引入字素簇分段。关键是把限制写进校验和测试;一旦允许
emoji、组合音标或多语言文本,就必须重新选择切分口径。 -
文本审核功能从“判断是否回文”扩展为“找出最长的不重复连续片段”,原来的两端双指针还能直接复用吗?
两端收缩适合比较首尾关系,不能直接维护任意连续区间内的重复约束。应改用滑动窗口,并借助
Map记录字符位置或计数;窗口中的字符单位仍须与产品定义保持一致,否则Unicode输入会产生偏差。 -
线上只有带组合重音的姓名出现长度校验和回文判断不一致,
ASCII与普通emoji测试都通过;你会怎样定位?先构造由基础字符和组合标记组成的最小样例,分别打印
length、Array.from()结果与字素簇分段结果。若两个功能采用了不同字符口径,应统一到同一分段层;规范化是否需要引入,则要由“相等”的业务定义决定。 -
日志分析要统计超长文本中每种符号的出现次数,团队在普通对象与
Map之间选型;你会提醒哪些边界?Map能直接以分段后的字符为键,并避免普通对象原型键带来的额外处理,适合表达频次表。真正影响结果的仍是分段单位和输入规模;完整统计需要随不同字符数增长的空间,无法仅靠换容器消除。