LeetCode 151. 反转字符串中的单词

4 阅读3分钟

LeetCode 151. 反转字符串中的单词

摘要

LeetCode 151 反转字符串中的单词题解,采用整体反转 + 局部反转的方式,先反转整个字符串,再逐个反转每个单词,同时去除多余空格,时间复杂度 O(n),空间复杂度 O(1)。

标签

#算法 #LeetCode #字符串 #双指针 #题解

目录

  1. 题目描述
  2. 易错点
  3. 思路
  4. 编写代码

1. 题目描述

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

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

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

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

示例 1:

text

输入:s = "the sky is blue"
输出:"blue is sky the"

示例 2:

text

输入:s = "  hello world  "
输出:"world hello"
解释:反转后的字符串不能包含前导和尾随空格。

示例 3:

text

输入:s = "a good   example"
输出:"example good a"
解释:单词间的多个空格要缩减为单个空格。

提示:

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

2. 易错点

  1. 需要处理多余空格:前导空格、尾随空格、单词间的多个空格
  2. 反转整个字符串后,单词顺序颠倒,但每个单词内部的字符也是颠倒的,需要再次反转每个单词
  3. 在去除空格并填充新字符串时,需注意最后不要多添加一个空格
  4. 需要原地修改字符串并截断(在末尾添加 '\0'
  5. 双指针移动时要防止越界,并正确处理指针位置
  6. 原字符串可能长度较大,需要保证算法时间复杂度 O(n)

3. 思路

采用整体反转 + 局部反转的方法,分为三步:

  1. 反转整个字符串:将字符串整体反转,此时单词顺序变为正确顺序,但每个单词内部的字符也是反的

  2. 去除多余空格并移动单词

    • 使用快慢指针 i 和 j 遍历原字符串
    • i 用于扫描原字符串,跳过所有空格找到单词开头
    • j 用于在新位置上重建字符串
    • 将单词字符复制到 j 位置,然后在单词后添加一个空格(最后一个单词除外)
  3. 反转每个单词

    • 在刚刚构建的新字符串中,对每个单词(由空格分隔)进行反转,使其恢复正常顺序
  4. 截断字符串:最后在 j 位置添加 '\0',完成原地修改

该方法时间复杂度 O(n),空间复杂度 O(1),符合题目进阶要求。


4. 编写代码

c 运行

c

char* reverseWords(char* s) {
    int len = strlen(s);
    // 1. 反转整个字符串
    for (int i = 0, j = len - 1; i < j; i++, j--) {
        char tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
    }
    // 2. 去除多余空格并移动单词,同时反转每个单词
    int i = 0, j = 0; 
    while (i < len) {
        // 跳过空格,找到单词起始
        while (i < len && s[i] == ' ') i++;
        if (i >= len) break;
        int start = j;
        // 复制单词字符
        while (i < len && s[i] != ' ') {
            s[j++] = s[i++];
        }
        int end = j - 1;
        // 反转当前单词
        while (start < end) {
            char tmp = s[start];
            s[start] = s[end];
            s[end] = tmp;
            start++;
            end--;
        }
        // 在单词后添加一个空格(最后一个单词后不加,稍后处理)
        if (j < len) s[j++] = ' ';
    }
    // 去除末尾多余的空格
    if (j > 0 && s[j-1] == ' ') j--;
    s[j] = '\0';
    return s;
}