前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • 前端算法面试

    • 数组基础
    • 栈、队列与链表
    • 树与二叉树
    • 二叉树递归遍历
    • 时间与空间复杂度
    • 数组高频题
    • 字符串高频题
      • 基本算法技能
        • 反转字符串
        • 判断一个字符串是否是回文字符串
      • 高频真题解读
        • 回文字符串的衍生问题
        • 字符串匹配问题——正则表达式初相见
        • 正则表达式更进一步——字符串与数字之间的转换问题
    • 链表基础题
    • 链表双指针
    • 环形链表
    • 栈的经典应用
    • 队列与双端队列
    • DFS 与 BFS
    • 递归与回溯
    • 二叉树高频题
    • 二叉搜索树
    • 平衡二叉树
    • 堆与堆排序
    • 基础排序算法
    • 归并与快速排序
    • 动态规划入门
    • 动态规划进阶
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

字符串的应用——真题归纳与解读|算法篇

字符串在算法面试中,单独考察的机会并不多,同样倾向于和一些经典算法(后面会讲的)结合来体现区分度。步子不能跨太大,不然容易扯着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 样例。

面试官追问

追问 1用户资料页限制昵称最多 10 个“字符”,但 '😀'.length 得到 2;产品、前端和后端在评审时必须先统一什么口径?
参考回答

必须先明确“字符”指 UTF-16 code unit、Unicode code point,还是用户看到的字素簇。JavaScript 的 length 按 code unit 计数,Array.from() 按 code point 拆分;面向视觉字符的限制通常还需 Intl.Segmenter。

追问 2搜索框只处理英文小写字母,候选人仍为每次输入建立复杂分词对象;你会如何权衡正确性与实现成本?
参考回答

若输入契约确实限定为英文小写字母,按索引读取已经能满足字符语义,没有必要引入字素簇分段。关键是把限制写进校验和测试;一旦允许 emoji、组合音标或多语言文本,就必须重新选择切分口径。

追问 3文本审核功能从“判断是否回文”扩展为“找出最长的不重复连续片段”,原来的两端双指针还能直接复用吗?
参考回答

两端收缩适合比较首尾关系,不能直接维护任意连续区间内的重复约束。应改用滑动窗口,并借助 Map 记录字符位置或计数;窗口中的字符单位仍须与产品定义保持一致,否则 Unicode 输入会产生偏差。

追问 4线上只有带组合重音的姓名出现长度校验和回文判断不一致,ASCII 与普通 emoji 测试都通过;你会怎样定位?
参考回答

先构造由基础字符和组合标记组成的最小样例,分别打印 length、Array.from() 结果与字素簇分段结果。若两个功能采用了不同字符口径,应统一到同一分段层;规范化是否需要引入,则要由“相等”的业务定义决定。

追问 5日志分析要统计超长文本中每种符号的出现次数,团队在普通对象与 Map 之间选型;你会提醒哪些边界?
参考回答

Map 能直接以分段后的字符为键,并避免普通对象原型键带来的额外处理,适合表达频次表。真正影响结果的仍是分段单位和输入规模;完整统计需要随不同字符数增长的空间,无法仅靠换容器消除。

# 反转字符串

30 秒速记

  • JavaScript 字符串不可变,反转会创建新结果;最常见实现是拆分字符、原地交换、再拼接
  • split('') 按 UTF-16 code unit 拆分,会破坏由代理对组成的 emoji;Array.from() 或 [...text] 至少按 code point 拆分
  • code point 仍不等于用户看到的字素簇,组合音标、家庭 emoji 等要用 Intl.Segmenter
  • 双指针交换时间 O(n)、额外空间 O(n),因为字符串不可变且需要字符数组
  • 面试前先确认题目处理 ASCII、小写字母、Unicode code point,还是用户可见字符

反转字符串通常先转成字符数组,再用左右指针交换,最后通过 join('') 拼回字符串。 因为 JavaScript 字符串不可变,这个过程的时间和额外空间都是 O(n)。纯英文可以用 split(''),但它会拆坏 emoji 的代理对;处理 Unicode code point 时应改用 Array.from()。如果要求按用户看到的字符反转,组合音标和家庭 emoji 还要通过 Intl.Segmenter 按字素簇分段。

原文的 split('').reverse() 对纯英文成立,但会把 emoji 的代理对拆开。若题目只要求按 Unicode code point 反转,可以这样写:

function reverseText(text) {
  const chars = Array.from(text)
  let left = 0
  let right = chars.length - 1
  while (left < right) {
    ;[chars[left], chars[right]] = [chars[right], chars[left]]
    left += 1
    right -= 1
  }
  return chars.join('')
}

console.log(reverseText('A😀B')) // B😀A
@前端进阶之旅: 代码已经复制到剪贴板

Array.from() 能保住单个 emoji,却不能保证组合字素。例如 e 加组合重音可能仍被拆开;面向用户文本时用 new Intl.Segmenter(locale, { granularity: 'grapheme' }) 分段。算法时间 O(n),字符数组和结果占 O(n) 空间。

在 JS 中,反转字符串我们直接调相关 API 即可,相信不少同学都能手到擒来:

// 定义被反转的字符串 
const str = 'juejin'  
// 定义反转后的字符串
const res = str.split('').reverse().join('')

console.log(res) // nijeuj
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1昵称编辑页把 A😀B 用 split('').reverse().join('') 处理后出现乱码,而纯英文测试正常;你会怎样解释这段代码的失败点?
参考回答

split('') 按 UTF-16 code unit 拆分,部分 emoji 由代理对组成,反转后代理对顺序被破坏。若需求是按 Unicode code point 反转,可先用 Array.from(text);这仍不保证组合字素完整。

追问 2前端需要实现按 code point 反转,代码评审要求避免不断执行 result = char + result;你会给出什么实现?
参考回答

先用 Array.from(text) 得到字符数组,再以 left、right 双指针原地交换,最后执行一次 join('')。算法遍历为 O(n),数组与结果占 O(n) 空间;JavaScript 字符串不可变,不能承诺真正的零额外输出空间。

追问 3产品把“反转昵称”改成按用户看到的字符反转,输入可能包含 e 加组合重音;仅把 split('') 换成 Array.from() 足够吗?
参考回答

不够,Array.from() 保护的是 Unicode code point,而组合重音可能与基础字符属于同一个字素簇。应使用 Intl.Segmenter(locale, { granularity: 'grapheme' }) 分段后再反转;具体 locale 需要与产品文本规则一致。

追问 4线上故障只发生在少量多语言昵称,排查时你发现存储值、页面显示和反转结果的长度各不相同;应该先收集什么证据?
参考回答

先保留原始字符串,并分别查看 code unit、code point 和字素簇三种切分结果,避免只依据页面视觉判断。再核对校验、存储和反转是否使用同一字符口径;若上游还改变了文本表示,需要单独确认相等规则。

追问 5面试官要求“O(1) 额外空间反转字符串”,候选人直接在 JavaScript 字符串上交换索引;你会如何纠正这个约束冲突?
参考回答

JavaScript 字符串不可变,索引位置不能被原地交换,生成反转字符串必然需要新的结果存储。若题目把输入改为可变字符数组,双指针交换可做到算法辅助空间 O(1);但字符数组和最终输出本身仍占空间。

(这段代码需要你非常熟悉,一些公司一面为了试水,有时会单独考这个操作)。

# 判断一个字符串是否是回文字符串

30 秒速记

  • 回文判断使用左右指针比较对称位置,首次不等即可返回 false,无需真的构造完整反转串
  • 时间 O(n)、辅助空间按可索引字符表示而定;ASCII 字符串可直接索引,Unicode 文本先明确字符口径
  • “忽略大小写、空格和标点”不是回文定义自带条件,必须由题目契约决定并在比较前规范化
  • 规范化可能改变字符数量与语义,例如 é 有预组合和组合形式,可按需求使用 normalize('NFC')
  • 空串和单字符通常视为回文,但应在函数契约或测试中明确

判断回文字符串,我一般用左右指针比较对称位置,遇到第一处不同就直接返回 false。 这样不需要构造反转字符串,时间复杂度是 O(n);ASCII 字符串可以直接按下标访问,Unicode 文本则要先明确比较口径。忽略大小写、空格和标点并不是回文判断的默认规则,只有题目明确要求时才做预处理。像 é 还可能存在不同编码形式,可按需求先调用 normalize('NFC'),空串和单字符通常视为回文。

← 数组高频题链表基础题 →

fe
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • 前端算法面试

    • 数组基础
    • 栈、队列与链表
    • 树与二叉树
    • 二叉树递归遍历
    • 时间与空间复杂度
    • 数组高频题
    • 字符串高频题
      • 基本算法技能
        • 反转字符串
        • 判断一个字符串是否是回文字符串
      • 高频真题解读
        • 回文字符串的衍生问题
        • 字符串匹配问题——正则表达式初相见
        • 正则表达式更进一步——字符串与数字之间的转换问题
    • 链表基础题
    • 链表双指针
    • 环形链表
    • 栈的经典应用
    • 队列与双端队列
    • DFS 与 BFS
    • 递归与回溯
    • 二叉树高频题
    • 二叉搜索树
    • 平衡二叉树
    • 堆与堆排序
    • 基础排序算法
    • 归并与快速排序
    • 动态规划入门
    • 动态规划进阶