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

文章介绍了如何使用双指针技巧在不同语言中去除字符串中的空格并反转单词。对于字符串不可变的语言,需要先转化数据结构;而对于可变字符串,可以在原地操作。提供了三种不同的实现版本,包括覆盖法、双端队列等策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
在这里插入图片描述

方法一:双指针

思路和算法
我们也可以不使用语言中的 API,而是自己编写对应的函数。在不同语言中,这些函数实现是不一样的,主要的差别是有些语言的字符串不可变(如 Java 和 Python),有些语言的字符串可变(如 C++)。

对于字符串不可变的语言,首先得把字符串转化成其他可变的数据结构,同时还需要在转化的过程中去除空格。

请添加图片描述
对于字符串可变的语言,就不需要再额外开辟空间了,直接在字符串上原地实现。在这种情况下,反转字符和去除空格可以一起完成。
请添加图片描述

代码如下:

class Solution {
public:
	// 版本一:覆盖法消除空格
    void eraseSpaces(string &s) {
        int n = s.size();
        int slowIndex = 0;
        int fastIndex = 0;

        // 去除前导空格
        while (fastIndex < n and s[fastIndex] == ' ') {
            fastIndex ++;
        }
        
        // 去除单词间的多个空格
        for (; fastIndex < n; fastIndex ++) {
            if (fastIndex > 1                       // 此时快指针指向一个字母,大于1是因为s中至少存在一个单词
                    and s[fastIndex] == ' ' 
                    and s[fastIndex] == s[fastIndex - 1]) {
                        continue;
                    }
            s[slowIndex++] = s[fastIndex];
        }

        // 去除尾随空格
        if (slowIndex > 1 and s[slowIndex - 1] == ' ') {
            s.resize(slowIndex - 1);
        } else {
            s.resize(slowIndex);
        }
    }

    string reverseWords(string s) {
        eraseSpaces(s);                 // 去除多余的空格
        reverse(s.begin(), s.end());    // 反转整个字符串
        // [start, end)前闭后开区间
        int start = 0;              // 反转字符串中单词的开头位置
        int end = 0;                // 反转字符串中单词的结束位置
        bool entry = false;      // 标记枚举反转字符串的过程中是否进入单词区间
        int n = s.size();
        for (int i = 0; i < n; i++) {
            // 确定单词的开头位置
            if ((!entry) or (s[i - 1] == ' ' and s[i] != ' ')) {
                start = i;
                entry = true;
            }
            
            // 确定单词的结束位置
            if (entry and s[i] == ' ' and s[i - 1] != ' ') {
                end = i;
                entry = false;
                reverse(s.begin() + start, s.begin() + end);
            }

            // 最后一个结尾单词之后后
            if (entry and (i == n -1) and s[i] != ' ') {
                entry = false;
                reverse(s.begin() + start, s.end());
            }
        }  

        return s;
    }
// 当然这里的主函数reverseWords写的有一些冗余的,可以精简一些,精简之后的主函数为:
    /* 主函数简单写法
    string reverseWords(string s) {
        eraseSpaces(s);
        reverse(s.begin(), s.end());
        for(int i = 0; i < s.size(); i++) {
            int j = i;
            // 查找单词间的空格,翻转单词
            while(j < s.size() && s[j] != ' ') j++;
            reverse(s.begin() + i, s.begin() + j);
            i = j;
        }
        return s;
    }
    */
};

或者,通过增加一个字符串s2的空间,也可实现去除空格的函数,如下所示:

// 版本二
void eraseSpaces(string &s) {
        int left = 0;
        int right = s.size() - 1;
        // 去掉字符串开头的空白字符
        while (left <= right && s[left] == ' ') {
            ++left;
        }

        // 去掉字符串末尾的空白字符
        while (left <= right && s[right] == ' ') {
            --right;
        }

        // 将字符串间多余的空白字符去除
        string s2 = "";
        while (left <= right) {
            char c = s[left];
            if (c != ' ') {
                s2 += c;
            } else if (s2[(int)s2.size() - 1] != ' ') {
                s2 += c;
            }	
            left ++;
        }
        s = s2;
 }

去除空格的函数可以进一步简化,如下所示:

// 版本三
void removeExtraSpaces(string& s) {//去除所有空格并在相邻单词之间添加空格, 快慢指针。
    int slow = 0;   //整体思想参考https://programmercarl.com/0027.移除元素.html
    for (int fast = 0; fast < s.size(); ++fast) { //
        if (s[fast] != ' ') { //遇到非空格就处理,即删除所有空格。
            if (slow != 0) s[slow++] = ' '; //手动控制空格,给单词之间添加空格。slow != 0说明不是第一个单词,需要在单词前添加空格。
            while (fast < s.size() && s[fast] != ' ') { //补上该单词,遇到空格说明单词结束。
                s[slow++] = s[fast++];
            }
        }
    }
    s.resize(slow); //slow的大小即为去除多余空格后的大小。
}

在这里插入图片描述

方法二:双端队列

思路和算法
由于双端队列支持从队列头部插入的方法,因此我们可以沿着字符串一个一个单词处理,然后将单词压入队列的头部,再将队列转成字符串即可。
请添加图片描述

class Solution {
public:
    string reverseWords(string s) {
        int left = 0, right = s.size() - 1;
        // 去掉字符串开头的空白字符
        while (left <= right && s[left] == ' ') ++left;

        // 去掉字符串末尾的空白字符
        while (left <= right && s[right] == ' ') --right;

        deque<string> d;
        string word;

        while (left <= right) {
            char c = s[left];
            if (word.size() && c == ' ') {
                // 将单词 push 到队列的头部
                d.push_front(move(word));
                word = "";
            }
            else if (c != ' ') {
                word += c;
            }
            ++left;
        }
        // 最后一个单词后的空格已被去掉,所以需要手动添加
        d.push_front(move(word));
        
        string ans;		// 默认为""
        while (!d.empty()) {
            ans += d.front();
            d.pop_front();
            if (!d.empty()) ans += ' ';
        }
        return ans;
    }
};

在这里插入图片描述
参考资料
https://leetcode.cn/problems/reverse-words-in-a-string/solution/fan-zhuan-zi-fu-chuan-li-de-dan-ci-by-leetcode-sol/
https://leetcode.cn/problems/reverse-words-in-a-string/solution/dai-ma-sui-xiang-lu-dai-ni-gao-ding-zi-f-hg23/

### C语言实现LeetCode 151题(反转字符串中的单词) 对于给定的任务,在C语言中解决该问题的一种方法是通过手动处理字符串并利用辅助函数来完成特定操作。下面展示了一种可能的解决方案,其中包含了如何定义必要的功能以及它们是如何协同工作的解释。 #### 完整代码示例 ```c #include <stdio.h> #include <string.h> void trim(char *str) { char *end; while (isspace((unsigned char)*str)) str++; end = str + strlen(str) - 1; while(end > str && isspace((unsigned char)*end)) end--; *(end+1) = '\0'; } void reverseString(char* start, char* end){ while(start<end){ char temp=*start; *start++=*end; *end--=temp; } } char* reverseWords(char* s) { int length=strlen(s); if(length==0)return ""; // Trim leading and trailing spaces trim(s); char *result=(char*)malloc(strlen(s)+2); // Extra space for potential extra space at the end and null terminator result[0]='\0'; char word[50]; // Assuming no single word will exceed this limit int index=0; for(int i=0;i<=length;i++){ if(i==length || s[i]==' '){ if(index>0){ reverseString(word,word+index-1); strcat(result,word); if(i!=length)strcat(result," "); memset(word,'\0',sizeof(word)); index=0; } }else{ word[index++]=s[i]; } } return result; } ``` 此程序首先移除了输入字符串两端多余的空白字符[^1]。接着遍历整个字符串,每当遇到空格或到达字符串结尾时,就调用`reverseString()`函数翻转当前收集到的一个完整的词,并将其追加到最终的结果串后面。为了防止最后多出不必要的空格,在每次添加新词之前会检查当前位置是否为原字符串的实际末端位置[^2]。 注意这里假设单个词语长度不会超过预设的最大值(这里是49),如果存在更长的情况,则需要调整数组大小或者采用动态分配的方式存储临时变量`word`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值