YCBlogs 字符串算法实战:翻转句子中单词顺序(先整体反转再局部反转的经典两步法)

发布时间:2026/10/12 4:01:17
YCBlogs 字符串算法实战:翻转句子中单词顺序(先整体反转再局部反转的经典两步法)
教程技术博客文档【免费下载链接】YCBlogs技术博客笔记大汇总包括Java基础线程并发数据结构Android技术博客等等常用设计模式常见的算法网络协议知识点部分flutter笔记还包括平时开发中遇到的bug汇总当然也在工作之余收集了大量的面试题长期更新维护并且修正持续完善……开源的文件是markdown格式的转载请注明出处谢谢项目地址https://gitcode.com/gh_mirrors/yc/YCBlogs点击查看免费下载本文是 YCBlogs 技术博客仓库中 leetcode/10.字符串/08.翻转单词顺序.md 的完整技术解读。围绕输入一个英文句子翻转其中单词的顺序但保持每个单词内部字符顺序不变这一高频算法题文章将完整给出题目约束、两步翻转的核心思想、可运行的 Java 实现与测试用例并结合仓库中同主题的 01.翻转字符串 与 09.左旋转字符串 两篇姊妹题剖析字符反转函数复用与复杂度来源帮助读者一次掌握字符串区间反转这一基础原语在多个变体题中的迁移运用。01. 题目要求问题描述输入一个英文句子翻转句子中单词的顺序但单词内字符的顺序不变。简化约定为简单起见标点符号和普通字母一样处理即逗号、句号等一律视为普通字符参与翻转不单独识别词法单元。示例例如输入字符串I am a body , my name is yangchong.则输出yangchong. is name my , body a am I。观察示例输出可以确认题目的两个关键点句子整体顺序被反转I am a body变成了body a am I的倒序位置每个单词内部的字符排列保持不变body依然是bodyyangchong.依然是yangchong.标点跟随所在单词。02. 问题分析与核心思想两步翻转法这道题最直观的想法可能是先按空格切分单词再逆序拼接但这需要额外开辟存储空间且要小心处理多个空格与标点粘连的问题。仓库给出的经典解法采用**两步翻转Two-pass Reverse**策略完全在原地完成第一步翻转句子中所有字符。例如翻转I am a student. 中所有的字符得到.tneduts a m a I。此时不但翻转了句子中单词的顺序连单词内的字符顺序也被翻转了。第二步再翻转每个单词中字符的顺序。逐个找到单词边界对每个单词内部的字符区间再次反转就得到了student. a am I。这正是符合题目要求的输出。用公式表达即为reverse(整句) - reverse(单词1) - reverse(单词2) - ... - reverse(单词N)两次反转的效果互相抵消于单词内部而单词之间的相对顺序被彻底颠倒这正是该技巧的精妙之处不需要识别单词只依赖空格作为边界标记。2.1 与左旋转字符串的关联同一个区间反转原语这一思想在仓库的 09.左旋转字符串 中被以相同思路复用把字符串分为前后两部分先分别翻转两部分再翻转整个字符串即可把前 n 个字符移动到字符串尾部。两者共同依赖的底层能力就是将字符数组 data 中 start 到 end 之间的字符反转这一基础操作这也是本仓库字符串系列反复出现的核心原语。03. 实例代码完整实现与逐段讲解仓库给出的完整实现由两个方法组成reverseSentence主逻辑与reverse区间反转工具。3.1 区间反转工具方法 reverse/** * 将data中start到end之间的数字反转 * * param data * param start * param end */ public static void reverse(char[] data, int start, int end) { if (data null || data.length 1 || start 0 || end data.length || start end) { return; } while (start end) { char tmp data[start]; data[start] data[end]; data[end] tmp; start; end--; } }方法要点防御性校验data null、数组为空、start 0、end data.length越界、start end区间非法时直接返回保证任何调用方式都不会抛出数组越界异常原地交换通过一个临时变量tmp完成对称位置的字符交换从两端向中间收敛直到start end不返回值直接在传入的char[]上修改属于原地in-place操作因此主方法不需要接收返回值也能感知到反转结果。这与 01.翻转字符串 中reverseString(char[] data, int start, int end)的实现几乎一致区别仅在于该姊妹题返回了数组引用以便链式调用。由此可见区间反转是整个字符串翻转系列的基础设施理解了这一个方法系列题的主干就都通了。3.2 主逻辑方法 reverseSentence/** * 题目输入一个英文句子翻转句子中单词的顺序但单词内字啊的顺序不变。 * 为简单起见标点符号和普通字母一样处理。 * * param data * return */ public static char[] reverseSentence(char[] data) { if (data null || data.length 1) { return data; } reverse(data, 0, data.length - 1); int start 0; int end 0; while (start data.length) { if (data[start] ) { start; end; } else if (end data.length || data[end] ) { reverse(data, start, end - 1); end; start end; } else { end; } } return data; }3.3 主逻辑逐行推演整个while (start data.length)循环使用两个游标start单词起点与end单词终点探测游标以空格为分隔符识别出每一个单词区间并逐一反转循环体内三种分支的语义如下分支条件含义动作data[start] start指向空格start、end跳过该空格end data.length \|\| data[end] end到达数组末尾或探测到空格即找到了一个单词的右边界反转[start, end-1]区间然后end跳过空格start end定位下一个单词的起点其他情况end仍处于单词内部end继续向右探测对输入I am a body , my name is yangchong.的执行过程可以拆解为先整体反转得到.gnohcgnay si eman ym , ydob a ma I游标从下标 0 开始扫描遇到单词.gnohcgnay反转得到yangchong.跳过空格继续定位下一个单词si反转得is依次类推每遇到一个空格就反转前一段单词区间直到数组末尾最后一个单词I由end data.length分支兜底反转。最终输出yangchong. is name my , body a am I与题目要求的示例完全一致。3.4 边界情况说明data null || data.length 1直接原样返回不做任何处理避免空指针与越界连续多个空格每个空格都会被跳过空格分支逐一消费不会产生单词区间重叠或漏翻转句子以空格开头或结尾循环起始时的空格跳过逻辑与结尾处end data.length兜底逻辑都能正确处理标点符号按题目约定与普通字符同样处理因此yangchong.这类单词加标点的整体会被当作一个单词原样保留内部顺序。04. 测试代码与运行结果仓库给出了完整的可运行测试代码public static void main(String[] args){ String str1 I am a body , my name is yangchong.; char[] charArray str1.toCharArray(); char[] reverseSentence reverseSentence(charArray); StringBuffer sb new StringBuffer(); for(int i0 ; ireverseSentence.length ; i) { sb.append(reverseSentence[i]); } System.out.println(yc------- sb.toString()); } //执行结果 yc-------yangchong. is name my , body a am I测试代码的验证路径为String通过toCharArray()转为char[]传入算法 → 算法原地修改数组 → 通过StringBuffer.append(char)逐个字符回拼为String并打印。控制台输出的yc-------yangchong. is name my , body a am I与题目示例完全吻合验证了算法的正确性。需要注意算法修改的是char[]数组本身因此charArray在调用reverseSentence之后内容已变测试中通过reverseSentence的返回值即同一个数组引用来重建字符串是正确且高效的做法。05. 复杂度分析与优化探讨5.1 时间与空间复杂度时间复杂度O(n)。整体反转遍历一次数组n 为字符串长度随后的单词扫描与反转过程中start与end两个游标合计至多遍历数组两次探测与反转共享同一趟扫描每个字符至多被交换常数次整体仍为线性复杂度。这一点可以从仓库 00.导向/03.时间复杂度 中只关注循环执行次数最多的代码的分析方法推导确认无论主循环内如何分支循环执行的次数始终与数组长度 n 成正比。空间复杂度O(1)。除输入数组本身外只使用了start、end、tmp等常数个变量属于严格的原地在位算法不依赖任何与 n 相关的额外存储。5.2 为什么不先切分单词一种常见思路是先按空格split成单词数组再逆序拼接但该方案存在两个问题一是需要额外 O(n) 的存储空间二是多个连续空格、首尾空格会造成空字符串元素需要在拼接时额外过滤逻辑反而更复杂。两步反转法用空格即边界的朴素规则统一处理了这些情况代价仅是两次 O(n) 的反转属于典型的时间换空间的工程权衡。5.3 一步到位的替代实现参考若题目允许使用语言内置工具例如 Java 的StringBuilder可以先用空格切分、逆序单词、再用空格拼接完成等效功能但该方式在空格数量不唯一时行为与本题按空格原样保留的约定存在差异。本题约定的标点与字母同等处理正是为了避开词法分析让两步反转法成为最契合题意的解法。在 leetcode/10.字符串 目录下还有 02.字符串替换空格空格替换为 %20、04.回文字符串 等字符串操作题与本文共同组成了该仓库的字符串算法练习体系读者可以顺路对照练习。06. 同源变体左旋转字符串中的三步反转两步反转法的思想在本仓库的 09.左旋转字符串 中被推广为三步反转实现如下节选自该文档public static char[] leftRotateString(char[] data, int n) { if (data null || n 0 || n data.length) { return data; } reverse(data, 0, data.length - 1); reverse(data, 0, data.length - n - 1); reverse(data, data.length - n, data.length - 1); return data; }其核心步骤为把字符串分成前 n 个字符与剩余字符两部分分别翻转这两部分对应代码中两次局部reverse翻转整个字符串即可得到左旋 n 位的结果。例如abcdefg左旋 2 位先翻转前后两部分得bagfedc再整体翻转得到cdefgab测试代码输入yangchong与数字 3输出gchongyan验证了正确性。对比可见翻转单词顺序是整体反转 按空格局部反转左旋转是按位置局部反转 整体反转两者互为镜像但底层复用的是同一个reverse工具方法。掌握这两道题就掌握了区间反转原语在字符串类算法中最典型的两种编排方式。07. 小结本文围绕 翻转单词顺序 完成了从题目约束、两步翻转思想、源码逐行讲解、测试验证到复杂度分析的全过程梳理并横向对照了仓库内 翻转字符串 与 左旋转字符串 两个同源变体。核心结论可以浓缩为三点两步翻转法是本题的最优解框架先整体反转打乱单词顺序再按空格逐词反转恢复单词内部顺序O(n) 时间、O(1) 空间、原地完成区间反转reverse(char[] data, int start, int end)是字符串翻转系列的公共原语被多道姊妹题复用值得作为基本功掌握边界处理决定代码健壮性空数组、连续空格、首尾空格、末尾单词兜底反转是面试中考察代码完整性的常见细节。读者可将本文中的reverseSentence与reverse方法直接复制到本地 Java 环境中运行验证也可前往仓库 blog/06.算法大汇总 中的字符串专题查看更多同类练习。赞分享教程技术博客文档【免费下载链接】YCBlogs技术博客笔记大汇总包括Java基础线程并发数据结构Android技术博客等等常用设计模式常见的算法网络协议知识点部分flutter笔记还包括平时开发中遇到的bug汇总当然也在工作之余收集了大量的面试题长期更新维护并且修正持续完善……开源的文件是markdown格式的转载请注明出处谢谢项目地址https://gitcode.com/gh_mirrors/yc/YCBlogs点击查看免费下载相关推荐AlgoNote 算法通关手册LeetCode 186「反转字符串中的单词 II」——双指针 两次反转的原地字符串算法解析AlgoNote 算法通关手册LeetCode 186「反转字符串中的单词 II」——双指针 两次反转的原地字符串算法解析 导读 本篇基于「算法通关手册」教程文档知识库Mistral-7B中文对话模型实战部署完整方案从零到生产级深度优化Mistral 7B中文对话模型实战部署完整方案从零到生产级深度优化 面对当前AI应用部署中普遍存在的GPU资源紧张、推理速度慢、部署复杂度高等挑战Mist网盘直链下载怎么装LinkSwift 九大网盘直链获取完整指南网盘直链下载怎么装LinkSwift 九大网盘直链获取完整指南 打开百度网盘分享页准备取一个 2GB 的视频速度条停在个位数官方客户端又要求你装整套 Ap前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考