当前位置: 首页 > news >正文

面试经典150题[021]:反转字符串中的单词(LeetCode 151)

反转字符串中的单词(LeetCode 151)

题目链接:反转字符串中的单词(LeetCode 151)
难度:中等

1. 题目描述

给你一个字符串 s,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将单词分隔开。
返回单词顺序颠倒且单词之间用 单个空格 连接的结果字符串。

注意

  • 输入字符串 s 中可能存在前导空格、尾随空格或单词间的多个空格。
  • 返回结果中,单词间仅用单个空格分隔,不包含任何额外空格。

要求

  • 1 <= s.length <= 10^4
  • s 包含英文大小写字母、数字和空格 ’ ’
  • s 中至少存在一个单词

示例

输入: s = "the sky is blue"
输出: "blue is sky the"
输入: s = "  hello world  "
输出: "world hello"
输入: s = "a good   example"
输出: "example good a"

进阶:如果字符串在使用的编程语言中是可变数据类型,尝试使用 O(1) 额外空间复杂度的原地解法。

2. 问题分析

2.1 规律

  • 需要反转字符串中单词的顺序,但保持每个单词内部字符的顺序。
  • 输入字符串可能包含多余空格(前导、尾随、单词间多个空格),输出需保证单词间只有单个空格。
  • 核心问题:如何高效处理空格并反转单词顺序?
  • 进阶要求 O(1) 空间复杂度,意味着不能使用额外的数据结构(如数组存储单词),需要在原字符串上操作。

2.2 解题思路

思路 1:分步处理(非原地,O(n) 空间)
  1. 清理空格:将字符串按空格分割成单词数组,过滤掉空字符串。
  2. 反转单词顺序:将单词数组反转。
  3. 拼接结果:用单个空格连接单词,生成最终字符串。

此方法简单直观,但需要额外空间存储单词数组,不满足进阶要求。

思路 2:原地解法(O(1) 空间,针对可变字符串)
  1. 反转整个字符串:先将整个字符串的字符反转(包括空格)。
  2. 反转每个单词:遍历反转后的字符串,找到每个单词的起止位置,单独反转单词内部字符。
  3. 清理多余空格:在原字符串上移除前导、尾随空格及单词间多余空格,调整为单个空格。

此方法适合可变字符串(如 C++ 的 std::string 或字符数组),满足进阶要求。

贪心思路(基于思路 2)
  • 反转整个字符串:将字符串视为字符序列,直接反转。
  • 逐个反转单词:基于空格识别单词边界,反转每个单词。
  • 清理空格:从左到右扫描,保留单词间的单个空格,移除多余空格。
  • 关键点:所有操作都在原字符串上进行,额外空间仅为常数级别。

2.3 示例

s = " hello world " 为例:

  • 步骤 1:反转整个字符串
    原字符串:" hello world "
    反转后:" dlrow olleh "
  • 步骤 2:反转每个单词
    找到单词 "dlrow",反转为 "world"
    找到单词 "olleh",反转为 "hello"
    结果:" world hello "
  • 步骤 3:清理空格
    移除前导、尾随空格,单词间保留单个空格:
    结果:"world hello"

3. 代码实现

Python(思路 1:非原地,简单实现)

class Solution:def reverseWords(self, s: str) -> str:# 按空格分割,过滤空字符串words = [word for word in s.split() if word]# 反转单词数组words.reverse()# 用单个空格连接return " ".join(words)

C++(思路 2:原地解法,O(1) 空间)

class Solution {
public:string reverseWords(string s) {int n = s.size();// 步骤 1:反转整个字符串reverse(s.begin(), s.end());// 步骤 2:反转每个单词int i = 0;while (i < n) {// 跳过空格while (i < n && s[i] == ' ') i++;if (i == n) break;// 找到单词的起始和结束位置int start = i;while (i < n && s[i] != ' ') i++;int end = i - 1;// 反转单词while (start < end) {swap(s[start++], s[end--]);}}// 步骤 3:清理空格int write = 0; // 写入位置i = 0; // 读取位置while (i < n) {// 跳过前导空格while (i < n && s[i] == ' ') i++;if (i == n) break;// 写入单词if (write > 0) s[write++] = ' '; // 单词前加单个空格while (i < n && s[i] != ' ') {s[write++] = s[i++];}}// 调整字符串长度s.resize(write);return s;}
};

4. 复杂度分析

思路 1(Python 非原地)

  • 时间复杂度:O(n),其中 n 是字符串长度。分割、反转、拼接操作均为线性时间。
  • 空间复杂度:O(n),需要存储单词数组。

思路 2(C++ 原地)

  • 时间复杂度:O(n)
    • 反转整个字符串:O(n)
    • 反转每个单词:总计 O(n)
    • 清理空格:O(n)
  • 空间复杂度:O(1),仅使用常数额外空间(不计输入字符串的修改)。

5. 总结

  • 简单解法:分割单词、反转、拼接,适合快速实现,但空间复杂度为 O(n)。
  • 原地解法:反转整个字符串 → 反转单词 → 清理空格,满足进阶要求,空间复杂度 O(1)。
  • 关键点
    • 处理多余空格是重点,需确保单词间仅一个空格。
    • 原地解法依赖字符串的可变性,适合 C++ 等语言,Python 字符串不可变无法完全实现 O(1) 空间。
  • 扩展:可参考类似问题,如 LeetCode 186(反转字符串中的单词 II,仅限字符数组)。

复习

面试经典150题[006]:旋转数组(LeetCode 189)
面试经典150题[007]:买卖股票的最佳时机(LeetCode 121)
面试经典150题[014]:加油站(LeetCode 134)

http://www.dtcms.com/a/361222.html

相关文章:

  • 【XR技术概念科普】VST(视频透视)vs OST(光学透视):解码MR头显的两种核心技术路径
  • 「数据获取」《中国住户调查年鉴》(2000-2024)(获取方式看绑定的资源)
  • SQLark:一款面向信创应用开发者的数据库开发和管理工具
  • Jmeter实现参数化的4种方式
  • Windows神器,按键屏蔽
  • 【机器学习学习笔记】pandas基础
  • (纯新手教学)计算机视觉(opencv)实战十二——模板匹配(cv2.matchTemplate)
  • UE角色取消被Decal影响
  • Jetson AGX Orin平台R36.3.0版本1080P25fps MIPI相机图像采集异常调试记录
  • 基于单片机电动车充电桩/充电车棚环境监测设计
  • 基于RS-485接口的芯片的FPGA驱动程序
  • 吴恩达机器学习作业十二:协同过滤(电影推荐系统)
  • 广电手机卡到底好不好?
  • Git基础使用和PR贡献
  • .Net程序员就业现状以及学习路线图(二)
  • Android面试指南(六)
  • 大模型落地全流程实践:从技术选型到企业级部署
  • 音视频开发入门:FFmpeg vs GStreamer,新手该如何选择?
  • 松灵斯坦福Mobile ALOHA同款 | 通过低成本全身远程操作实现双手机器人移动操控学习
  • 01数据结构-红黑树
  • 永磁同步电机无速度算法--高频脉振方波注入法(测量轴系转子位置误差信号解耦处理)
  • Spark引擎中RDD的性质
  • 【牛客JZ31】—栈的压入弹出序列判断算法详解
  • 【73页PPT】MES应用介绍(附下载方式)
  • SpringBoot @RefreshScope 注解的极致玩法
  • SpringCloud-服务注册-服务发现
  • AI瘦身狂魔!微软推出原生1-bit大模型,性能不减,内存仅需同行零头!
  • 博0进化版
  • 9月校招难题怎么解?AI面试精准匹配人才
  • 系统架构设计师备考第12天——计算机语言-建模形式化语言