算法 --字符串
字符串算法题本质上就是“数组操作”加上“字符编码转换”以及“人类手工计算过程的代码化”。例题剖析题目一最长公共前缀解法一class Solution { public: string longestCommonPrefix(vectorstring strs) { if (strs.empty()) return ; string ret strs[0]; for (int i 1; i strs.size(); i) { ret findCommon(ret, strs[i]); } return ret; } string findCommon(string s1, string s2) { int i 0; while (i min(s1.size(), s2.size()) s1[i] s2[i]) i; return s1.substr(0, i); } };代码逻辑解析这段代码采用了逐个比较的思想初始化string ret strs[0];将结果字符串ret初始化为字符串数组中的第一个字符串。这是一个常见的策略把第一个字符串当作“基准”。遍历数组for (int i 1; i strs.size(); i)从第二个字符串开始依次遍历数组中的每一个字符串。寻找公共部分ret findCommon(ret, strs[i]);对于每一个遍历到的字符串strs[i]调用findCommon函数来求它与当前ret的最长公共前缀并将结果更新回ret。这意味着ret的长度会随着遍历过程不断缩短最终保留下来的就是所有字符串的公共前缀。辅助函数findCommon使用while循环条件是两个字符串都没有越界i min(s1.size(), s2.size())且当前字符相同s1[i] s2[i]。循环结束时i的值就是公共前缀的长度。最后通过s1.substr(0, i)截取并返回公共前缀。复杂度分析时间复杂度O(N×M)。其中 N 是字符串数组的长度M 是字符串的平均长度。最坏情况下需要比较所有字符串的每一个字符。空间复杂度O(1)不考虑返回值占用的空间。代码只使用了常数级别的额外变量i。解法二class Solution { public: string longestCommonPrefix(vectorstring strs) { if (strs.empty()) return ; for (int i 0; i strs[0].size(); i) { char tmp strs[0][i]; for (int j 1; j strs.size(); j) { if (i strs[j].size() || tmp ! strs[j][i]) return strs[0].substr(0, i); } } return strs[0]; } };代码逻辑解析这段代码的核心思想是同时比较所有字符串的同一列同一个索引位置。外层循环列遍历for(int i 0; i strs[0].size(); i)以第一个字符串strs[0]作为基准。循环变量i代表当前正在比较的字符索引列。因为公共前缀不可能比第一个字符串还长所以以它的长度作为循环上限。取基准字符char tmp strs[0][i];取出第一个字符串在第i个位置的字符作为这一列的对比基准。内层循环行遍历for(int j 1; j strs.size(); j)从第二个字符串开始依次遍历数组中的其他所有字符串检查它们在第i个位置的字符。不匹配检测与返回if(i strs[j].size() || tmp ! strs[j][i])这是代码中最关键的一步判断当前列是否终止i strs[j].size()这意味着字符串strs[j]的长度比i还要短已经越界了。既然某个字符串已经到头了那公共前缀最远也就只能到i了。tmp ! strs[j][i]当前对比的字符与基准字符不同说明公共前缀断了。如果满足上述任一条件立刻返回strs[0].substr(0, i)即截取第一个字符串从 0 开始长度为i的部分这正是当前找到的最长公共前缀。循环结束返回return strs[0];如果外层循环完整执行完毕都没有触发内层的提前返回说明第一个字符串strs[0]就是所有字符串的公共前缀直接返回它即可。复杂度分析时间复杂度O(N×M)。最坏情况下所有字符串完全相同需要比较每一个字符串的每一个字符。其中 N 是字符串数量M 是字符串平均长度。空间复杂度O(1)不计返回值占用的空间。只使用了常数个额外变量。算法对比纵向扫描 vs 两两比较解法二优点在发现不匹配时能尽早退出。例如输入是[abcdefg, abcde, abc]当i3即比较第4个字符d时内层循环发现i strs[2].size()长度为3索引最大为2立刻就能返回abc不需要像两两比较那样每次都截取一遍字符串。在数据量大、差异出现早的情况下效率往往更高。缺点如果第一个字符串特别长而其他字符串特别短内层循环的越界判断会频繁触发。解法一优点思路极其直观容易想到。缺点需要不断生成新的字符串对象substr会产生新对象可能会有额外的性能开销。题目二最长回文子串class Solution { public: string longestPalindrome(string s) { if (s.empty()) return ; int begin 0, len 0; // 依次枚举所有的中点 for (int i 0; i s.size(); i) { // 奇数长度 auto [l1, len1] expandAroundCenter(s, i, i); // 偶数长度 auto [l2, len2] expandAroundCenter(s, i, i 1); if (len1 len) { len len1; begin l1; } if (len2 len) { len len2; begin l2; } } return s.substr(begin, len); } // 返回 {起始索引, 长度} pairint, int expandAroundCenter(const string s, int left, int right) { while (left 0 right s.size() s[left] s[right]) { left--; right; } return {left 1, (right - 1) - (left 1) 1}; } };核心思想中心扩展算法回文串有一个天然的特性它是对称的。因此我们可以遍历字符串中的每一个字符把它当作回文串的“中心”然后向两边同时扩展看看能扩展多长。这里有一个关键点回文串的长度可能是奇数也可能是偶数。奇数长度如aba中心是一个字符。偶数长度如abba中心是两个字符之间的“缝隙”。这段代码正是分别处理了这两种情况。复杂度分析时间复杂度O(N2)。其中 N 是字符串的长度。我们遍历了 N 个中心点每个中心点向两边扩展最多需要 O(N)的时间。对于本题 N≤1000 的数据规模O(N2) 是可以接受的大约 100 万次操作。空间复杂度O(1)。只使用了常数级别的额外变量没有开辟与 N 相关的额外空间。题目三二进制求和class Solution { public: string addBinary(string a, string b) { string ret; int cur1 a.size() - 1, cur2 b.size() - 1, t 0; while (cur1 0 || cur2 0 || t) { if (cur1 0) t a[cur1--] - 0; if (cur2 0) t b[cur2--] - 0; ret t % 2 0; t / 2; } reverse(ret.begin(), ret.end()); return ret; } };核心思想模拟竖式加法逢二进一十进制的加法是逢十进一二进制则是逢二进一。我们需要从两个字符串的末尾最低位开始依次向前遍历逐位相加并处理进位。复杂度分析时间复杂度O(max(N,M))。其中 NN 和 MM 分别是字符串a和b的长度。我们最多只需要遍历较长的那个字符串一次。空间复杂度O(max(N,M))。主要消耗在存储结果字符串ret上。如果不算返回值额外的空间只有几个整型变量是 O(1)。题目四字符串相乘class Solution { public: string multiply(string num1, string num2) { int m num1.size(), n num2.size(); reverse(num1.begin(), num1.end()); reverse(num2.begin(), num2.end()); vectorint tmp(m n - 1); for (int i 0; i m; i) { for (int j 0; j n; j) { tmp[i j] (num1[i] - 0) * (num2[j] - 0); } } int cur 0, t 0; string ret; while (cur m n - 1 || t) { if (cur m n - 1) t tmp[cur]; ret t % 10 0; t / 10; } while (ret.size() 1 ret.back() 0) ret.pop_back(); reverse(ret.begin(), ret.end()); return ret; } };核心原理坐标映射假设有两个数字num1长度为m反转后记为n1索引i从 0 到m-1代表从低位到高位。num2长度为n反转后记为n2索引j从 0 到n-1代表从低位到高位。在竖式乘法中n1[i]和n2[j]相乘的结果应该放在最终结果的第i j位上。为了避开复杂的进位处理我们使用一个数组tmp来临时存储每个位置上的乘积之和暂时不管进位。数组tmp的最大长度是多少两个m位数和n位数相乘结果最多是m n位比如 99 * 99 9801224位。但因为i最大为m-1j最大为n-1所以ij最大为mn-2。因此初始化tmp大小为m n - 1就足够容纳所有累加结果了。辅助理解图无进位相乘累加阶段1 2 3 (n1反转后是 3, 2, 1) x 4 5 6 (n2反转后是 6, 5, 4) ----------------- 18 15 12 (3分别乘6,5,4放入tmp[0],tmp[1],tmp[2]) 27 22 8 (2分别乘6,5,4放入tmp[1],tmp[2],tmp[3]) 28 13 4 (1分别乘6,5,4放入tmp[2],tmp[3],tmp[4]) ----------------- 18 27 28 13 4 (这就是最终的tmp数组)注意此时tmp数组里存的数字是“错位相加”的结果还没有处理进位。统一处理进位现在我们得到了tmp [18, 27, 28, 13, 4]。从左到右从低位到高位处理进位。逻辑是当前位的值 tmp[cur] 上一轮的进位。保留个位作为结果十位作为进位传给下一位。处理前导零并反转ret 88065末尾是5没有多余的前导零。反转ret得到56088。返回结果56088。复杂度分析时间复杂度O(M×N)。双重循环遍历了两个字符串的所有位。对于本题 M,N≤200M,N≤200计算量大约在 4 万次左右运行极快。空间复杂度O(MN)。主要是tmp数组和结果字符串ret占用的空间。这段代码它将复杂的进位逻辑剥离了出来。如果我们在双层循环里直接处理进位代码会变得异常复杂且容易出错因为一个乘积可能会影响后面好几个位。而“先全部乘完累加最后统一处理进位”的思路将问题分成了两个简单的子问题大大降低了编码难度。注意事项写字符串代码时90% 的 Bug 都出在以下细节上空字符串与边界检查永远要先判断字符串是否为空s.empty()或s.length() 0。例如求最长公共前缀时如果数组为空直接访问strs[0]会导致程序崩溃。索引与长度的“差一错误”长度为n的字符串有效索引是0到n-1。在中心扩展算法中循环结束后的真实回文长度通常是right - left - 1真实起始位置是left 1这里极容易算错。字符与整数的转换字符0到9的 ASCII 码是连续的。数字字符转整数用c - 0整数转字符用n 0。判断字符是否为字母或数字可以使用 C 内置函数isalnum(c)、isdigit(c)、isalpha(c)。字符串拼接的性能陷阱在 C 中s s c在循环中会产生大量临时对象导致时间复杂度退化到 O(N2)容易超时。正确做法使用s c或s.push_back(c)。如果是倒序生成的字符串如大数运算最后统一用reverse(s.begin(), s.end())反转。善用内置函数但别滥用substrC 的string提供了很多好用的函数如find()、substr()、reverse()。但substr()会创建新的字符串对象在循环中频繁使用会导致性能下降。能用索引解决的就尽量用索引。

相关新闻

STM32+OpenMV嵌入式矩形识别实战:从预处理到串口协议

STM32+OpenMV嵌入式矩形识别实战:从预处理到串口协议

简介:本资源是一套基于STM32F103C8T6与OPENMV协同实现黑色矩形识别的嵌入式视觉项目,面向嵌入式初学者、智能车/机器人方向学生及课程设计实践者,解决图像识别结果实时回传与坐标解析这一典型跨平台通信问题。压缩包共90个文件,含…

2026/10/14 18:58:13 阅读更多 →
洛阳 GEO 优化是什么?一文看懂生成式引擎优化

洛阳 GEO 优化是什么?一文看懂生成式引擎优化

GEO(Generative Engine Optimization,生成式引擎优化) 是通过结构化内容、实体一致性与权威信源建设,让品牌信息被豆包、DeepSeek、腾讯元宝、Kimi、文心一言等生成式 AI 平台检索、采信并引用的优化方法。在洛阳本地场景中&#…

2026/10/14 18:58:13 阅读更多 →
涉密资质投入产出分析模型:时间成本、四块成本构成与 ROI 决策框架

涉密资质投入产出分析模型:时间成本、四块成本构成与 ROI 决策框架

定义: 涉密资质投入产出分析,是指企业在决策是否申请涉密信息系统集成资质、军工保密资质或国家秘密载体印制资质时,对时间成本、经济成本和预期收益进行量化评估的决策方法。其核心是将资质申请的 “达标周期 审批周期” 与 “首年投入 持…

2026/10/14 18:58:13 阅读更多 →

最新新闻

Apollo-11 自动化任务调度框架:状态机与插件化设计实践

Apollo-11 自动化任务调度框架:状态机与插件化设计实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 1:13:56 阅读更多 →
微信积分商城H5落地指南:授权、账务与并发防超卖全解析

微信积分商城H5落地指南:授权、账务与并发防超卖全解析

简介:这是一套面向移动端微信积分兑换商城的H5项目源码,定位于帮助开发者快速搭建具备签到、游戏积分、代金券兑换等功能的积分商城页面。基于HTML5技术实现,适配手机微信环境,适用于电商运营、会员营销等场景,也适合前…

2026/10/15 1:13:56 阅读更多 →
大数据驱动的人工智能医疗:从数据治理到临床落地的实践指南

大数据驱动的人工智能医疗:从数据治理到临床落地的实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 1:13:56 阅读更多 →
NumPy学习指南:从ndarray到广播,掌握高效数组计算

NumPy学习指南:从ndarray到广播,掌握高效数组计算

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 1:13:56 阅读更多 →
漂亮通用界面:设计令牌与组件化的多项目UI工程路线

漂亮通用界面:设计令牌与组件化的多项目UI工程路线

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 1:13:56 阅读更多 →
C#自动更新程序源码:客户端软件安全升级的架构与实现要点

C#自动更新程序源码:客户端软件安全升级的架构与实现要点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 1:12:55 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →