【数据结构和算法】反转字符串中的单词

简介: 给你一个字符串s,请你反转字符串中单词的顺序。单词是由非空格字符组成的字符串。s中使用至少一个空格将字符串中的单词分隔开。返回单词顺序颠倒且单词之间用单个空格连接的结果字符串。注意:输入字符串s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

其他系列文章导航

Java基础合集

数据结构与算法合集

设计模式合集

多线程合集

分布式合集

ES合集


文章目录

其他系列文章导航

文章目录

前言

一、题目描述

二、题解

2.1 方法一:双指针

2.2 方法二:分割 + 倒序

三、代码

3.1 方法一:双指针

3.2 方法二:分割 + 倒序

四、复杂度分析

4.1 方法一:双指针

4.2 方法二:分割 + 倒序


前言

这是力扣的151题,难度为中等,解题方案有很多种,本文讲解我认为最奇妙的两种。


一、题目描述

给你一个字符串 s ,请你反转字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

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

示例 1:

输入:s = "the sky is blue"

输出:"blue is sky the"

示例 2:

输入:s = "  hello world  "

输出:"world hello"

解释:反转后的字符串中不能存在前导空格和尾随空格。


示例 3:

输入:s = "a good   example"

输出:"example good a"

解释:如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。


提示:

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

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


    二、题解

    2.1 方法一:双指针

    思路与算法:

      • 先去首尾空格。
      • 倒序遍历字符串 s ,记录单词左右索引边界 i , j 。
      • 每确定一个单词的边界,则将其添加至单词列表 res 。
      • 最终,将单词列表拼接为字符串,去掉尾部空格,并返回即可。

      2.2 方法二:分割 + 倒序

      思路与算法:

      以空格为分割符完成字符串分割后,若两单词间有 x>1 个空格,则在单词列表 strs 中,此两单词间会多出 x−1 个 “空单词” (即 "" )。

      解决方法:倒序遍历单词列表,并将单词逐个添加至 StringBuilder ,遇到空单词时跳过。


      三、代码

      3.1 方法一:双指针

      Java版本:

      class Solution {
          public String reverseWords(String s) {
              s = s.trim();                                          // 删除首尾空格
              int j = s.length() - 1, i = j;
              StringBuilder res = new StringBuilder();
              while (i >= 0) {
                  while (i >= 0 && s.charAt(i) != ' ') i--;          // 搜索首个空格
                  res.append(s.substring(i + 1, j + 1)).append(" "); // 添加单词
                  while (i >= 0 && s.charAt(i) == ' ') i--;          // 跳过单词间空格
                  j = i;                                             // j 指向下个单词的尾字符
              }
              return res.toString().trim();                          // 转化为字符串并返回
          }
      }

      image.gif

      Python版本:

      class Solution:
          def reverseWords(self, s: str) -> str:
              s = s.strip()                            # 删除首尾空格
              i = j = len(s) - 1
              res = []
              while i >= 0:
                  while i >= 0 and s[i] != ' ': i -= 1 # 搜索首个空格
                  res.append(s[i + 1: j + 1])          # 添加单词
                  while i >= 0 and s[i] == ' ': i -= 1 # 跳过单词间空格
                  j = i                                # j 指向下个单词的尾字符
              return ' '.join(res)                     # 拼接并返回

      image.gif

      3.2 方法二:分割 + 倒序

      Java版本:

      class Solution {
          public String reverseWords(String s) {
              String[] split = s.trim().split(" ");
              StringBuilder res = new StringBuilder();
              for (int i = split.length - 1; i >= 0; i--) {
                  if (!split[i].equals("")) {
                      res.append(split[i]).append(" ");
                  }
              }
              return res.toString().trim();
          }
      }

      image.gif

      Python版本:

      class Solution:
          def reverseWords(self, s: str) -> str:
              return ' '.join(s.strip().split()[::-1])

      image.gif


      四、复杂度分析

      4.1 方法一:双指针

        • 时间复杂度 O(N) : 其中 N 为字符串 s 的长度,线性遍历字符串。
        • 空间复杂度 O(N) : 新建的 list(Python) 或 StringBuilder(Java) 中的字符串总长度 ≤ N ,占用 O(N) 大小的额外空间。

        4.2 方法二:分割 + 倒序

          • 时间复杂度 O(N) : 总体为线性时间复杂度,各函数时间复杂度和参考资料链接如下。
            • split() 方法: 为 O(N) 。
            • trim() 和 strip() 方法: 最差情况下(当字符串全为空格时),为 O(N) 。
            • join() 方法: 为 O(N) 。
            • reverse() 方法: 为 O(N) 。
              • 空间复杂度 O(N) : 单词列表 strs 占用线性大小的额外空间。
              目录
              相关文章
              |
              2月前
              |
              算法 数据处理 C语言
              C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
              本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
              70 1
              |
              2月前
              |
              机器学习/深度学习 算法 数据挖掘
              K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
              K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
              165 4
              |
              16天前
              |
              存储 算法 测试技术
              【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
              本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
              39 2
              |
              1月前
              |
              存储 运维 监控
              探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
              在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
              57 20
              |
              2月前
              |
              存储 算法 搜索推荐
              Python 中数据结构和算法的关系
              数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
              |
              2月前
              |
              数据采集 存储 算法
              Python 中的数据结构和算法优化策略
              Python中的数据结构和算法如何进行优化?
              |
              2月前
              |
              算法
              数据结构之路由表查找算法(深度优先搜索和宽度优先搜索)
              在网络通信中,路由表用于指导数据包的传输路径。本文介绍了两种常用的路由表查找算法——深度优先算法(DFS)和宽度优先算法(BFS)。DFS使用栈实现,适合路径问题;BFS使用队列,保证找到最短路径。两者均能有效查找路由信息,但适用场景不同,需根据具体需求选择。文中还提供了这两种算法的核心代码及测试结果,验证了算法的有效性。
              132 23
              |
              2月前
              |
              并行计算 算法 测试技术
              C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
              C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
              84 1
              |
              2月前
              |
              C语言
              【数据结构】栈和队列(c语言实现)(附源码)
              本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
              292 9
              |
              2月前
              |
              存储 算法
              非递归实现后序遍历时,如何避免栈溢出?
              后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
              45 1

              热门文章

              最新文章