摘要:原句:"I am a student."单词序列是:["I", "am", "a", "student."]反转后:["student.", "a", "am", "I"]拼接结果:"student. a am I"
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。
示例:
输入:"I am a student."输出:"student. a am I"注意: 句子中可能包含多个空格(如首尾空格、连续空格),你的程序需要能正确处理这些边界情况。
这个问题的核心是 “反转单词的顺序”,而不是反转字符。
我们来一步步理解:
原句:"I am a student."
单词序列是:["I", "am", "a", "student."]
反转后:["student.", "a", "am", "I"]
拼接结果:"student. a am I"
所以,关键在于:
按空格分割字符串成单词列表;反转这个列表;再用空格重新拼接。听起来很简单?但题目往往有陷阱,比如:
句子前后有空格怎么办?中间有多个连续空格怎么办?空字符串或全是空格的字符串怎么处理?这些就是我们需要特别注意的边界条件。
我们提供两种主流解法:语言特性法(简洁) 和 双指针法(高效)。
这是最直观、代码量最少的方法,适合快速AC(Accepted)。
核心思想:
使用 split 将字符串按空白字符分割,它会自动忽略所有空格(包括多个连续空格);使用 reversed 或切片 [::-1] 反转单词列表;使用 ' '.join 重新拼接。# -*- coding:utf-8 -*-class Solution:def ReverseSentence(self, s):# 特殊情况:空字符串或只含空格if not s or not s.strip:return s# 分割、反转、拼接words = s.splitreversed_words = ' '.join(reversed(words))return reversed_words代码解析:
s.split:不带参数时,按任意空白字符分割,并自动过滤空字符串;reversed(words):返回一个反转的迭代器;' '.join(...):用单个空格连接所有单词。优点: 代码简洁,逻辑清晰。
缺点: 依赖高级语言特性,面试官可能希望你手写逻辑。
如果我们不能使用 split,或者想展示扎实的基本功,就应该使用双指针从右往左遍历,手动提取单词。
算法步骤:
从字符串末尾开始,用两个指针 i 和 j;j 指向当前单词的末尾,i 向前移动寻找空格;当 s[i] 为空格时,说明 i+1 到 j 是一个完整的单词,加入结果;跳过连续空格,继续向前;最后处理第一个单词(可能没有前置空格)。图解过程:
字符串: " I am a student. "索引: 012345678901234567↑ ↑ ↑i j (末尾)步骤:1. j 指向最后一个字符,i 从 j-1 开始左移;2. 找到空格,提取 s[i+1:j+1] → "student."3. i 继续左移,跳过多余空格;4. 找到下一个空格,提取 "a"5. 以此类推...# -*- coding:utf-8 -*-class Solution:def ReverseSentence(self, s):if not s:return s# 去除首尾空格,转换为列表便于操作(实际不需要)# 我们直接用字符串切片result = i = j = len(s) - 1while i >= 0:# 找到单词末尾(跳过空格)while i >= 0 and s[i] == ' ':i -= 1if i = 0 and s[i] != ' ':i -= 1# 此时 i 在空格处,单词是 s[i+1:j+1]result.append(s[i+1:j+1])# 所有单词已提取,用空格连接return ' '.join(result)C++ 实现(双指针)
class Solution {public:string ReverseSentence(string s) {string result = "";int i = s.length - 1, j = s.length - 1;while (i >= 0) {// 跳过空格while (i >= 0 && s[i] == ' ')i--;if (i = 0 && s[i] != ' ')i--;// 提取单词result += s.substr(i+1, j-i);result += ' ';}// 去掉最后多余的空格if (!result.empty)result.pop_back;return result;}};四、关键点与陷阱问题 解决方案 首尾空格 双指针法中 while 跳过即可 多个连续空格 split 自动处理;双指针法通过循环跳过 空字符串或全空格 提前判断 if not s or s.strip == "" 结果末尾多一个空格 C++ 实现中最后 pop_back 去掉 效率问题 双指针法时间 O(n),空间 O(n),已是最优
五、拓展思考如果要求单词内部也反转?那就是“整体反转 + 局部反转”:先整个字符串反转;再逐个单词内部反转。这是另一道经典题:“旋转字符串” 的变种。能否原地修改?
在 C++ 中,如果字符串可变,可以尝试原地操作,但通常需要额外空间存储结果,不现实。性能对比:split + reverse + join:代码短,适合生产;双指针:空间利用率高,面试推荐。
方法 时间复杂度 空间复杂度 适用场景 内置函数法 O(n) O(n) 快速AC、脚本开发 双指针法 O(n) O(n) 面试展示、深入理解
核心思想:
反转单词顺序的本质,是将字符串视为单词的栈:先进后出。
我们从右往左扫描,每找到一个单词就“压入”结果列表,最终自然形成反转顺序。
七、结语字符串处理的基本功;边界条件的把控能力;对语言特性的理解;双指针技巧的应用。无论是用 split 一行解决,还是手写双指针,都要清楚背后的逻辑。
来源:码农世界