news 2026/5/20 14:54:16

字符串算法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
字符串算法

系列文章目录

《JavaScript 基础与进阶笔记》(前期偏基础巩固与常见面试点,后续进入闭包、异步、工程化等进阶主题)

  • 第 01 篇:数据类型与类型判断
  • 第 02 篇:变量声明与作用域
  • 第 03 篇:闭包与高阶函数
  • 第 04 篇:函数工厂
  • 第 05 篇:this 指向与绑定
  • 第 06 篇:原型与原型链
  • 第 07 篇:类与继承
  • 第 08 篇:JS 执行机制与异步队列
  • 第 09 篇:数组常用方法
  • 第 10 篇:字符串算法(本文)

文章目录

  • 系列文章目录
  • 前言
  • 一、预备:不可变与遍历方式
  • 二、反转字符串
  • 三、回文判断
  • 四、最长公共子串(连续)
  • 五、最长回文子串
  • 六、KMP:思路与 `next` 数组
  • 七、滑动窗口:无重复字符的最长子串
  • 八、简易模板引擎
  • 九、易混淆点归纳
  • 十、思考与练习
  • 总结

前言

字符串处理在面试与工程里同样高频:判断回文、求公共子串、模式匹配、以及把模板里的占位符替换成真实数据。许多题目依托双指针(头尾夹逼、快慢指针)或滑动窗口(维护区间性质),在此基础上再谈复杂度才算完整。本篇按「反转 → 回文 → 公共子串 / 最长回文子串 → KMP 思想 → 简易模板引擎」展开,与大纲「第二阶段:常用算法与手写题」第 10 节对齐;算法以 JavaScript 书写,必要时点出与 Unicode 相关的边界。


一、预备:不可变与遍历方式

  1. 字符串不可变:对字符串按下标赋值(在严格模式或一般赋值场景)不会改写原串,需通过切片拼接得到新串。
  2. 访问字符s[i]得到的是UTF-16 码元; emoji、部分汉字可能占两个码元,若题目涉及「按字符」而非「按码元」计数,需考虑[...s]Array.from(s)或国际化 API(本篇例题以 ASCII / 基本多文种平面内的常规输入为主)。
  3. 工具方法slicesubstringsplitreplaceincludesindexOf等可与手写逻辑对照使用(详见第 9 篇思路),面试手写题仍建议练「双指针 + 自行比较」。

二、反转字符串

双指针:左l = 0、右r = n - 1,交换s[l]s[r],直至l >= r。字符串需先转成数组再交换,最后再join

constreverseString=(str)=>{consta=[...str];letl=0;letr=a.length-1;while(l<r){[a[l],a[r]]=[a[r],a[l]];l++;r--;}returna.join("");};reverseString("hello");// "olleh"

内置[...str].reverse().join("")或按题意使用Array.from。时间复杂度O(n),额外空间O(n)(存放字符数组)。


三、回文判断

定义:正读与反读相同(忽略大小写、仅看字母数字时常需先规范化)。

双指针:规范化后,从两端向中间比较;遇不相同即返回false

constisPalindrome=(s)=>{constt=s.toLowerCase().replace(/[^a-z0-9]/g,"");letl=0;letr=t.length-1;while(l<r){if(t[l++]!==t[r--])returnfalse;}returntrue;};isPalindrome("A man, a plan, a canal: Panama");// true

时间复杂度O(n)。若不要求过滤非字母数字,直接对原串双指针即可。


四、最长公共子串(连续)

最长公共子序列(不必连续)不同,子串要求在主串中连续出现。

动态规划:设dp[i][j]表示以a[i-1]b[j-1]结尾的最长公共子串长度;若a[i-1] === b[j-1]dp[i][j] = dp[i-1][j-1] + 1,否则为0。扫描过程中记录最大值与结束位置即可还原子串。时间O(mn),空间可压成O(min(m,n))的一维滚动(此处给出二维写法便于理解)。

constlongestCommonSubstring=(a,b)=>{constm=a.length;constn=b.length;letmaxLen=0;letend=0;constdp=Array.from({length:m+1},()=>newArray(n+1).fill(0));for(leti=1;i<=m;i++){for(letj=1;j<=n;j++){if(a[i-1]===b[j-1]){dp[i][j]=dp[i-1][j-1]+1;if(dp[i][j]>maxLen){maxLen=dp[i][j];end=i;}}}}returnmaxLen===0?"":a.slice(end-maxLen,end);};longestCommonSubstring("abcde","xbcdy");// "bcd"

五、最长回文子串

中心扩展:枚举每个中心(奇数长度中心为一个字符,偶数长度中心为两个字符之间),向两侧扩展,记录最长区间。复杂度O(n²),空间O(1)

constlongestPalindrome=(s)=>{constexpand=(l,r)=>{while(l>=0&&r<s.length&&s[l]===s[r]){l--;r++;}returnr-l-1;};letstart=0;letmax=0;for(leti=0;i<s.length;i++){constlenOdd=expand(i,i);constlenEven=expand(i,i+1);constlen=Math.max(lenOdd,lenEven);if(len>max){start=i-Math.floor((len-1)/2);max=len;}}returns.slice(start,start+max);};longestPalindrome("babad");// "bab" 或 "aba"

Manacher 算法可在线性时间内求解,篇幅所限这里不展开,面试问到再往「回文半径数组」方向准备即可。


六、KMP:思路与next数组

在文本text中找模式pattern,暴力做法是失配后text回溯,最坏O(nm)KMP在模式串上预处理next(或pi)数组:失配时pattern内部已匹配的前后缀告诉我们pattern右移多少格text指针不必回退,整体O(n + m)

next[j]的常见定义:pattern[0..next[j]-1]既是pattern[0..j-1]真前缀又是真后缀的最大长度。匹配时若text[i] !== pattern[j],令j = next[j]重试;若j为 0仍失配则i++

constbuildNext=(p)=>{constnext=[0];letj=0;for(leti=1;i<p.length;i++){while(j>0&&p[i]!==p[j])j=next[j-1];if(p[i]===p[j])j++;next[i]=j;}returnnext;};constkmpSearch=(text,pattern)=>{if(!pattern.length)return0;constnext=buildNext(pattern);letj=0;for(leti=0;i<text.length;i++){while(j>0&&text[i]!==pattern[j])j=next[j-1];if(text[i]===pattern[j])j++;if(j===pattern.length)returni-pattern.length+1;}return-1;};kmpSearch("ababcababa","aba");// 0

不同资料对next下标与「右移」表述略有差异,手写时先在纸上画一轮失配会更稳。


七、滑动窗口:无重复字符的最长子串

滑窗:右边界r每次右移一格,用Map / Set记录当前窗口内字符及其位置;若新字符已存在且索引≥ l,则左边界l跳到重复字符右侧。维护r - l + 1的最大值。

constlengthOfLongestSubstring=(s)=>{constmap=newMap();letl=0;letans=0;for(letr=0;r<s.length;r++){constc=s[r];if(map.has(c)&&map.get(c)>=l)l=map.get(c)+1;map.set(c,r);ans=Math.max(ans,r-l+1);}returnans;};lengthOfLongestSubstring("abcabcbb");// 3 ("abc")

时间O(n),每个位置最多被左、右指针各扫一次。


八、简易模板引擎

将形如${name}{{name}}的占位符替换为数据对象上的值,可用正则结合替换回调;缺失键时通常置空字符串或保留占位符(按产品约定)。

constrender=(tpl,data)=>tpl.replace(/\$\{(\w+)\}/g,(_,key)=>Object.prototype.hasOwnProperty.call(data,key)?String(data[key]):"",);consttpl="Hello, ${name}! Today is ${day}.";render(tpl,{name:"Tom",day:"Monday"});// "Hello, Tom! Today is Monday."

若要防止XSS,应对输出做转义或在框架层统一处理,不可仅做字符串拼接。


九、易混淆点归纳

  1. 子串 vs 子序列:子串必须连续;子序列只保持相对顺序。DP 状态转移写法不同。
  2. 双指针既可用于反转、回文,也可配合排序数组;滑窗适合「区间满足某性质」的最值问题。
  3. s[i]与 Unicode:按「用户可见字符」计数时,勿默认.length等于字符数
  4. KMP 与正则引擎:正则实现复杂得多;KMP 是确定有限状态下的经典教材模型。
  5. 复杂度口述:中心扩展回文O(n²);公共子串 DPO(mn);KMPO(n+m);滑窗O(n)

十、思考与练习

1.判断"0P"(零与大写 P)在「只保留字母数字并忽略大小写」的规则下是否为回文?

解析:规范化后为"0p",首尾0p不同,故为false

2.为何最长公共子串 DP 中失配时dp[i][j] = 0,而最长公共子序列失配时往往继承max(dp[i-1][j], dp[i][j-1])

解析:子串要求连续,一旦当前字符不相等,以当前位置结尾的公共连续段长度归零;子序列不要求连续,故可继承两侧已有长度。

3.无重复字符最长子串中,为何左边界要跳到map.get(c) + 1而不是只l++

解析:重复字符可能出现在当前窗口左侧之外,若仅l++无法一次性剔除窗口内全部非法内容;用上次出现位置 + 1才能保证窗口内无重复。


总结

  • 反转、回文多用双指针,注意规范化与 Unicode。
  • 最长公共子串DP或扩展理解;最长回文子串常用中心扩展 O(n²)
  • KMP通过next避免文本回溯,复杂度O(n+m)
  • 滑动窗口解决「不重复最长子串」等区间问题。
  • 模板替换可用正则replace;线上需配合安全转义。

下一篇计划整理常见手写题合集(上):深拷贝与浅拷贝、structuredClone、防抖与节流等,延续本阶段手写主线。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/20 14:54:07

HDPE土工膜直销厂家靠谱吗?带你揭秘厂家背后的真相!

HDPE土工膜直销厂家靠谱吗&#xff1f;带你揭秘厂家背后的真相&#xff01;在土工合成材料领域&#xff0c;HDPE土工膜是一种应用广泛的材料&#xff0c;其在防渗、隔离等方面有着出色表现。德州泽昌新材料有限公司作为一家知名的HDPE土工膜直销厂家&#xff0c;值得我们深入了…

作者头像 李华
网站建设 2026/5/20 14:54:03

ARM SMMU深度解析:从硬件原理到Linux驱动实战

1. 从GIC-600的分布式设计说起&#xff1a;为什么现代SoC需要SMMU&#xff1f;最近在梳理一个基于ARM Neoverse平台的大型SoC项目&#xff0c;其中关于中断控制器和内存管理单元的交互设计让我重新审视了SMMU&#xff08;System Memory Management Unit&#xff09;的价值。很多…

作者头像 李华
网站建设 2026/5/20 14:54:02

Mi-Create:小米穿戴设备个性化表盘设计的完整指南

Mi-Create&#xff1a;小米穿戴设备个性化表盘设计的完整指南 【免费下载链接】Mi-Create Unofficial watchface creator for Xiaomi wearables ~2021 and above 项目地址: https://gitcode.com/gh_mirrors/mi/Mi-Create 你是否厌倦了智能手表上那些千篇一律的默认表盘&…

作者头像 李华
网站建设 2026/5/20 14:53:54

如何利用Taotoken的模型广场为不同任务选择性价比最优模型

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 如何利用Taotoken的模型广场为不同任务选择性价比最优模型 面对摘要、翻译、代码生成等多种任务需求时&#xff0c;开发者常常需要…

作者头像 李华
网站建设 2026/5/20 14:53:47

5分钟上手!SD-PPP:让Photoshop秒变AI绘图神器的革命性插件

5分钟上手&#xff01;SD-PPP&#xff1a;让Photoshop秒变AI绘图神器的革命性插件 【免费下载链接】sd-ppp A Photoshop AI plugin 项目地址: https://gitcode.com/gh_mirrors/sd/sd-ppp 还在为Photoshop与AI绘图工具之间的频繁切换而烦恼吗&#xff1f;SD-PPP是一款革命…

作者头像 李华
网站建设 2026/5/20 14:53:41

国产类器官培养基与试剂品牌有哪些?精科类器官选购指南

最近几年类器官研究热度越来越高&#xff0c;很多生命科学领域的科研人员都在找靠谱的国产类器官培养基与试剂品牌&#xff0c;毕竟进口产品价格高、供货慢&#xff0c;售后对接也不方便&#xff0c;现在国产的类器官培养技术已经非常成熟&#xff0c;完全能满足各类实验需求&a…

作者头像 李华