尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
算法通关手册题解:LeetCode 0722 删除注释——C++ 注释语法与双指针逐行模拟
教程文档知识库【免费下载链接】AlgoNote⛽️「算法通关手册」从零开始的「算法与数据结构」学习教程200 道「算法面试热门题目」1000 道「LeetCode 题目解析」持续更新中项目地址https://gitcode.com/gh_mirrors/le/AlgoNote点击查看免费下载本文是「算法通关手册」中 LeetCode 0722「删除注释」 题解的深入解读。题目要求删除一段 C 源码中的行注释//与块注释/* ... */并保持行结构原样返回。本文从注释语法与优先规则出发推导出基于块注释状态标志的逐字符模拟算法给出可直接运行的 Python 代码并结合复杂度分析与源码佐证帮助读者掌握这一类「跨行状态 逐行模拟」问题的通用解法。1. 题目信息与考查点题号0722LeetCode 编号完整题解位于 remove-comments.md标签数组、字符串原始文档标注难度中等输入形式source是一个字符串数组其中source[i]表示第i行源码等价于源码由\n分隔输出形式删除注释后以相同格式返回源代码数组删除后为空的字符串不输出即答案中每个字符串都非空在「算法通关手册」的 题解总览 中本题被归类为「数组、字符串」标签的中等难度题目属于字符串处理中典型的逐字符扫描与状态维护问题。2. 题目大意与注释语法规则给一个 C 程序删除程序中的注释。程序source是一个数组其中source[i]表示第i行源码每行源码由\n分隔。C 中存在两种注释风格行注释字符串//表示//及其右侧的其余字符都应被忽略块注释字符串/*表示从/*开始直到下一个非重叠出现的*/之间的所有字符都应被忽略。注意阅读顺序为从左到右「非重叠」意味着字符串/*/并不会结束块注释因为注释结尾*/与开头/*发生了重叠。规则中还明确了注释之间的优先级第一个有效注释优先于其他注释如果字符串//出现在块注释中它会被忽略不会开启新的行注释同样如果字符串/*出现在行注释或块注释中它也会被忽略。关于输入数据题目给出了明确的约束与保证1 source.length 10^30 source[i].length 80source[i]由可打印的 ASCII 字符组成每个块注释最终都会被闭合因此在行或块注释之外的/*总是开始新的注释给定的源码中不会出现单引号、双引号或其他控制字符例如source /* Not a comment. */;这类含字符串字面量的样例不会出现没有其他内容如定义或宏会干扰注释。最后一个关键特性是隐式换行符可以通过块注释删除。由于块注释可以跨越多行被块注释包裹的行间换行符也随之消失这一特性在示例 2 中体现得非常明显。3. 示例分析3.1 示例 1行注释与多行块注释共存输入: source [/*Test program */, int main(), { , // variable declaration , int a, b, c;, /* This is a test, multiline , comment for , testing */, a b c;, }] 输出: [int main(),{ , ,int a, b, c;,a b c;,}]原始代码编排如下/*Test program */ int main() { // variable declaration int a, b, c; /* This is a test multiline comment for testing */ a b c; }第 1 行的/*与第 6-9 行的/*表示块注释第 4 行的//表示行注释。删除注释后int main() { int a, b, c; a b c; }可以看到几个细节第 1 行被整个块注释删除直接不输出第 4 行// variable declaration之后的内容被忽略但行首的两个空格在//之前被保留因此输出 第 6-9 行的块注释跨 4 行删除后这几行全为空不输出输出结果与原文档给出的[int main(),{ , ,int a, b, c;,a b c;,}]完全一致。3.2 示例 2块注释吃掉换行符输入: source [a/*comment, line, more_comment*/b] 输出: [ab]原始的source字符串等价于a/*comment\nline\nmore_comment*/b。删除注释后被块注释包裹的两处换行符隐含换行符也被删除剩下的ab以换行符分隔成数组时就是[ab]。这正是「隐式换行符可以通过块注释删除」的实际体现也是本题区别于普通字符串题目的关键点块注释状态必须在行与行之间保持跨行状态。4. 解题思路基于块注释状态标志的逐字符模拟4.1 核心思想删除注释本质上是一个「逐字符扫描 状态维护」的过程。由于块注释可以跨越多行单靠逐行处理无法完成任务必须用一个跨行持久的状态标志记录当前是否处于块注释中。用状态机的视角来看整个处理过程只有两个状态正常代码状态不在块注释中此时可能遇到普通字符、/*进入块注释、//忽略本行剩余部分块注释状态此时唯一关心的是是否遇到*/退出块注释其余所有字符包括//、/*、换行一律忽略。4.2 实现步骤参照 remove-comments.md 中「思路 1模拟」的步骤使用一个标志in_block表示当前是否在块注释中遍历每一行的每个字符如果在块注释中查找*/结束块注释如果不在块注释中遇到/*进入块注释遇到//忽略该行剩余部分break否则将字符加入当前行如果当前行不为空且不在块注释中将其加入结果。这里有一个实现细节值得注意/*、//、*/都是双字符标记判断时必须同时检查i 1 len(line)防止越界并且匹配成功后下标要一次跳过两个字符i 2。4.3 为什么块注释中的//与/*会被忽略由于in_block状态为真时代码只会查找*/这一种双字符序列其余字符全部跳过因此块注释内部出现的//不会触发行注释逻辑、/*也不会嵌套开启新的块注释。这正是「第一个有效注释优先于其他注释」规则的代码级体现也符合题目保证「每个块注释最终都会被闭合」的设定。5. 完整代码实现以下代码完整继承自 remove-comments.md 的「思路 1」实现class Solution: def removeComments(self, source: List[str]) - List[str]: result [] in_block False # 是否在块注释中 current_line [] # 当前行的内容 for line in source: i 0 while i len(line): if in_block: # 在块注释中查找 */ if i 1 len(line) and line[i:i2] */: in_block False i 2 else: i 1 else: # 不在块注释中 if i 1 len(line) and line[i:i2] /*: # 进入块注释 in_block True i 2 elif i 1 len(line) and line[i:i2] //: # 行注释忽略该行剩余部分 break else: # 普通字符 current_line.append(line[i]) i 1 # 如果不在块注释中且当前行不为空加入结果 if not in_block and current_line: result.append(.join(current_line)) current_line [] return result6. 代码逐段拆解与正确性论证6.1 跨行状态变量in_blockin_block在每行循环结束后不会重置这是整个算法的灵魂。当一行以未闭合的/*结束时如示例 2 的第一行a/*comment下一行会带着in_block True继续扫描从而保证跨行块注释被完整跳过。6.2current_line的累积与冲刷current_line以字符列表形式累积普通字符避免频繁字符串拼接。每行处理完毕时若in_block True说明当前行正处在块注释内部这一行无论是空还是累积了内容理论上块注释内不会累积内容都不输出且不清空current_line若in_block False且current_line非空把当前行拼成字符串加入result并清空current_line若in_block False且current_line为空整行被注释或为空行不输出。注意current_line的清空时机只有行处理完毕且不在块注释中时才清空。如果一行以块注释开始并以块注释结束如x/*c*/y由于块注释内不会向current_line追加字符x、y会正确拼接在同一行中。6.3 双字符标记的边界判断所有双字符标记判断都带i 1 len(line)边界条件避免在行尾读取越界。匹配成功后的i 2保证不会重复消费已匹配的标记字符这是扫描类算法常见的易错点。6.4 正确性验证对照两个示例示例 1逐行执行结果输入行处理过程输出行/*Test program */第 0 位遇/*进入块注释随后遇*/退出current_line为空不输出int main()普通字符全部累积int main(){普通字符累积{// variable declaration行首两个空格累积遇//breakint a, b, c;普通字符累积int a, b, c;/* This is a test...testing */全程处于块注释状态不输出多行a b c;普通字符累积a b c;}普通字符累积}示例 2逐行执行结果输入行处理过程输出行a/*comment累积a遇/*进入块注释行末in_block True暂不输出line块注释状态整行跳过暂不输出more_comment*/b块注释状态中遇*/退出随后累积bab三行最终拼接出ab与题目输出[ab]一致验证了「块注释删除隐含换行符」的行为。7. 复杂度分析时间复杂度$O(n \times m)$其中 $n$ 是源代码的行数$m$ 是每行的平均长度。每个字符最多被访问一次两个双字符标记每次多消耗一个字符的检查仍为线性。空间复杂度$O(n \times m)$主要用于存储结果result辅助空间current_line与in_block为 $O(m)$ 与 $O(1)$。8. 思路小结一类「跨行状态模拟」题的通法本题看似是一道字符串处理题但其难点在于状态跨行块注释可以跨越多行因此单行内的正则替换或字符串分割无法正确处理。这类问题在「算法通关手册」的其他题解中也反复出现例如remove-comments.md 的姊妹题如 0727. 最小窗口子序列子串匹配同样需要在扫描中维护指针与状态手册的 04_string 章节从 字符串基础 讲起覆盖 Brute Force 朴素匹配、KMP 等字符串算法其对应的源码实现位于 codes/python/04_string/string_brute_force.py 与 codes/python/04_string/string_kmp.py读者可对照学习双指针逐字符扫描的通用技巧。解题通法总结凡是需要「根据前缀标记忽略一段文本、且标记可跨行」的题目都可以采用「持久状态标志 逐字符扫描」的框架——把跨行信息保存在状态变量中单行内只做局部判断行与行之间保持状态连续性。本题的in_block状态就是这一框架的典型实现掌握后即可迁移到其他词法扫描、注释剥离、语法高亮等场景。赞分享教程文档知识库【免费下载链接】AlgoNote⛽️「算法通关手册」从零开始的「算法与数据结构」学习教程200 道「算法面试热门题目」1000 道「LeetCode 题目解析」持续更新中项目地址https://gitcode.com/gh_mirrors/le/AlgoNote点击查看免费下载相关推荐删列造序LeetCode 0944题解AlgoNote 算法通关手册中的数组与字符串双指针模拟实战删列造序LeetCode 0944题解AlgoNote 算法通关手册中的数组与字符串双指针模拟实战 本篇题解来自「算法通关手册」AlgoNote项目教程文档知识库算法通关手册LeetCode 0006 Z 字形变换题解模拟法逐行重构与周期规律算法通关手册LeetCode 0006 Z 字形变换题解模拟法逐行重构与周期规律 Z 字形变换Zigzag Conversion是 LeetCode教程文档知识库AlgoNote 算法通关手册LeetCode 0763「划分字母区间」贪心 哈希表 双指针逐行精讲AlgoNote 算法通关手册LeetCode 0763「划分字母区间」贪心 哈希表 双指针逐行精讲 导读 本篇题解对应 AlgoNote算法通关教程文档知识库创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

双模型协作实现精准摔倒检测:YOLOv5框人+OpenPose看骨架

双模型协作实现精准摔倒检测:YOLOv5框人+OpenPose看骨架

简介:一份面向人工智能学习者的YOLOv5人体检测与OpenPose姿态检测综合项目包,聚焦摔倒检测场景,适合有Python基础、希望实践目标检测与姿态估计结合应用的开发者。压缩包共183个文件,包含75张jpg/jpeg样本图、39个py源码脚本、21个…

📅 2026/10/10 11:41:11
双向依赖对账:Archify 的静态扫描到底在查什么

双向依赖对账:Archify 的静态扫描到底在查什么

双向依赖对账:Archify 的静态扫描到底在查什么 【免费下载链接】archify Turn any idea, plan, or codebase into a beautiful interactive diagram. An agent skill for Claude Code, Codex, and more. 项目地址: https://gitcode.com/GitHub_Trending/arch/arch…

📅 2026/10/10 11:41:11
员工手册.doc 的结构化改造:从静态文件到可追溯版本体系

员工手册.doc 的结构化改造:从静态文件到可追溯版本体系

简介:周大福珠宝员工手册是一份面向品牌内部员工及新入职人员的规范化管理指南,涵盖企业文化、日常行为准则与人事制度等核心模块。手册以“诚信、专业、创新”为主线,明确公司简介、远景使命及核心价值观,同时细化着装规范、服务…

📅 2026/10/10 11:36:10
MORE NEWS

更多资讯

📰

用C#编写现代化构建系统:Nuke核心概念与CI/CD集成实践

如果你维护过一套构建脚本超过一年,你大概率经历过这些时刻:发布前要手动改版本号,CI 上跑了一半才发现某个 NuGet 源拉不下来,新同事接手看到几百行 PowerShell 或者 bash 直接劝退。我最早也是从固定顺序的 .bat 开始&#xff0…

📰

在Emacs中构建agent-shell:打造能自我进化的AI工作台

1. 从“快捷键”到“助手”:为什么我在 Emacs 里搭了个 agent-shell今年年初接手了一个内部工具链的整合项目,需要同时处理文档生成、依赖升级、日志分析和跨仓库代码评审。事情本身不复杂,但重复度极高,每个流程都要在终端、编辑…

📰

GRE隧道全解析:原理、配置与排错实战

先说个真实的场景:两年前我给一家公司做分支互联方案,A点在江苏、B点在浙江,两边内网都用了 192.168.1.0/24,访问线上系统要走运营商公网。按照常规思路,要么拉专线,要么在每个业务系统上做端口映射&#x…

📰

OpenSpec:用规范驱动开发,让AI编码不偏离共识

有人把OpenSpec和电力行业的“变电站一键顺控改造技术规范”混在一起,原因也不难理解:名字里带“Spec”和“技术规范”,听着就像一本厚重的标准文档。我以前也一度以为它是某种文档模板,真正用起来才发现,OpenSpec是一…

📰

OpenClaw卸载不干净?一份从进程到缓存的完整清理指南

OpenClaw这种跑在大模型边上的自动化助手,装的时候能折腾一整天——git clone、npm install、docker compose up、配Ollama、写API Key,每一步都有坑。等你想卸载的时候才发现,这坑比安装还深。我在Windows和Linux上分别部署过OpenClaw&#…

📰

家庭网络设备选型与配置指南:从光猫到AP的组网实战

从第一次把路由器拆开、看到里面那块小小的电路板开始,我就对“网络设备”这几个字上了头。你可能觉得路由器就是个插上电源、连上网线就能用的盒子,但真正把光猫、路由器、交换机、无线AP这些设备之间的关系理清楚,再把每个设备的参数、接口…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬