前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >字符串:花式反转还不够!

字符串:花式反转还不够!

作者头像
代码随想录
修改于 2020-10-09 12:36:57
修改于 2020-10-09 12:36:57
64400
代码可运行
举报
文章被收录于专栏:代码随想录代码随想录
运行总次数:0
代码可运行

本文:https://github.com/youngyangyang04/leetcode-master​已经收录,里面还有leetcode刷题攻略、各个类型经典题目刷题顺序、思维导图,可以fork到自己仓库,有空看一看一定会有所收获,如果对你有帮助也给一个star支持一下吧!

题目:151.翻转字符串里的单词

给定一个字符串,逐个翻转字符串中的每个单词。

示例 1: 输入: "the sky is blue" 输出: "blue is sky the"

示例 2: 输入: " hello world! " 输出: "world! hello" 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。

示例 3: 输入: "a good example" 输出: "example good a" 解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。

思路

「这道题目可以说是综合考察了字符串的多种操作。」

一些同学会使用split库函数,分隔单词,然后定义一个新的string字符串,最后再把单词倒序相加,那么这道题题目就是一道水题了,失去了它的意义。

所以这里我还是提高一下本题的难度:「不要使用辅助空间,空间复杂度要求为O(1)。」

不能使用辅助空间之后,那么只能在原字符串上下功夫了。

想一下,我们将整个字符串都反转过来,那么单词的顺序指定是倒序了,只不过单词本身也倒叙了,那么再把单词反转一下,单词就正过来了。

所以解题思路如下:

  • 移除多余空格
  • 将整个字符串反转
  • 将每个单词反转

如动画所示:

这样我们就完成了翻转字符串里的单词。

思路很明确了,我们说一说代码的实现细节,就拿移除多余空格来说,一些同学会上来写如下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void removeExtraSpaces(string& s) {
    for (int i = s.size() - 1; i > 0; i--) {
        if (s[i] == s[i - 1] && s[i] == ' ') {
            s.erase(s.begin() + i);
        }
    }
    // 删除字符串最后面的空格
    if (s.size() > 0 && s[s.size() - 1] == ' ') {
        s.erase(s.begin() + s.size() - 1);
    }
    // 删除字符串最前面的空格
    if (s.size() > 0 && s[0] == ' ') {
        s.erase(s.begin());
    }
}

逻辑很简单,从前向后遍历,遇到空格了就erase。

如果不仔细琢磨一下erase的时间复杂度,还以为以上的代码是O(n)的时间复杂度呢。

想一下真正的时间复杂度是多少,一个erase本来就是O(n)的操作,erase实现原理题目:数组:就移除个元素很难么?,最优的算法来移除元素也要O(n)。

erase操作上面还套了一个for循环,那么以上代码移除冗余空格的代码时间复杂度为O(n^2)。

那么使用双指针法来去移除空格,最后resize(重新设置)一下字符串的大小,就可以做到O(n)的时间复杂度。

如果对这个操作比较生疏了,可以再看一下这篇文章:数组:就移除个元素很难么?是如何移除元素的。

那么使用双指针来移除冗余空格代码如下:fastIndex走的快,slowIndex走的慢,最后slowIndex就标记着移除多余空格后新字符串的长度。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void removeExtraSpaces(string& s) {
    int slowIndex = 0, fastIndex = 0; // 定义快指针,慢指针
    // 去掉字符串前面的空格
    while (s.size() > 0 && fastIndex < s.size() && s[fastIndex] == ' ') {
        fastIndex++;
    }
    for (; fastIndex < s.size(); fastIndex++) {
        // 去掉字符串中间部分的冗余空格
        if (fastIndex - 1 > 0
                && s[fastIndex - 1] == s[fastIndex]
                && s[fastIndex] == ' ') {
            continue;
        } else {
            s[slowIndex++] = s[fastIndex];
        }
    }
    if (slowIndex - 1 > 0 && s[slowIndex - 1] == ' ') { // 去掉字符串末尾的空格
        s.resize(slowIndex - 1);
    } else {
        s.resize(slowIndex); // 重新设置字符串大小
    }
}

有的同学可能发现用erase来移除空格,在leetcode上性能也还行。主要是以下几点:

  1. leetcode上的测试集里,字符串的长度不够长,如果足够长,性能差距会非常明显。
  2. leetcode测的程序耗时不是很准确。

此时我们已经实现了removeExtraSpaces函数来移除冗余空格。

还做实现反转字符串的功能,支持反转字符串子区间,这个实现我们分别在字符串:这道题目,使用库函数一行代码搞定字符串:简单的反转还不够!里已经讲过了。

代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 反转字符串s中左闭又闭的区间[start, end]
void reverse(string& s, int start, int end) {
    for (int i = start, j = end; i < j; i++, j--) {
        swap(s[i], s[j]);
    }
}

本题C++整体代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Solution {
public:
    // 反转字符串s中左闭又闭的区间[start, end]
    void reverse(string& s, int start, int end) {
        for (int i = start, j = end; i < j; i++, j--) {
            swap(s[i], s[j]);
        }
    }

    // 移除冗余空格:使用双指针(快慢指针法)O(n)的算法
    void removeExtraSpaces(string& s) {
        int slowIndex = 0, fastIndex = 0; // 定义快指针,慢指针
        // 去掉字符串前面的空格
        while (s.size() > 0 && fastIndex < s.size() && s[fastIndex] == ' ') {
            fastIndex++;
        }
        for (; fastIndex < s.size(); fastIndex++) {
            // 去掉字符串中间部分的冗余空格
            if (fastIndex - 1 > 0
                    && s[fastIndex - 1] == s[fastIndex]
                    && s[fastIndex] == ' ') {
                continue;
            } else {
                s[slowIndex++] = s[fastIndex];
            }
        }
        if (slowIndex - 1 > 0 && s[slowIndex - 1] == ' ') { // 去掉字符串末尾的空格
            s.resize(slowIndex - 1);
        } else {
            s.resize(slowIndex); // 重新设置字符串大小
        }
    }

    string reverseWords(string s) {
        removeExtraSpaces(s); // 去掉冗余空格
        reverse(s, 0, s.size() - 1); // 将字符串全部反转
        int start = 0; // 反转的单词在字符串里起始位置
        int end = 0; // 反转的单词在字符串里终止位置
        bool entry = false; // 标记枚举字符串的过程中是否已经进入了单词区间
        for (int i = 0; i < s.size(); i++) { // 开始反转单词
            if ((!entry) || (s[i] != ' ' && s[i - 1] == ' ')) {
                start = i; // 确定单词起始位置
                entry = true; // 进入单词区间
            }
            // 单词后面有空格的情况,空格就是分词符
            if (entry && s[i] == ' ' && s[i - 1] != ' ') {
                end = i - 1; // 确定单词终止位置
                entry = false; // 结束单词区间
                reverse(s, start, end);
            }
            // 最后一个结尾单词之后没有空格的情况
            if (entry && (i == (s.size() - 1)) && s[i] != ' ' ) {
                end = i;// 确定单词终止位置
                entry = false; // 结束单词区间
                reverse(s, start, end);
            }
        }
        return s;
    }
};

在留言区留下你的思路吧!

我是程序员Carl,哈工大师兄,先后在腾讯和百度从事技术研发多年,利用工作之余重刷leetcode。

我的B站(里面有我讲解的算法视频以及编程相关知识):https://space.bilibili.com/525438321

我的githubhttps://github.com/youngyangyang04

更多 精彩算法文章尽在:代码随想录,关注后,回复「Java」「C++」「python」「简历模板」等等,有我整理多年的学习资料,可以加我  微信,备注「个人简介」+「组队刷题」,拉你进入刷题群(无任何广告,纯个人分享),每天一道经典题目分析,我选的每一道题目都不是孤立的,而是由浅入深一脉相承的,如果跟住节奏每篇连续着看,定会融会贯通。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-09-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 代码随想录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
这次我们翻转字符串里的单词
https://leetcode-cn.com/problems/reverse-words-in-a-string/
代码随想录
2021/07/16
8580
【代码随想录】二刷-字符串
字符串 如果想让这套题目有意义,就不要申请额外空间。 344.反转字符串 双指针 // 时间复杂度O(n),执行n/2次交换 // 空间复杂度O(1) class Solution { public: void reverseString(vector<char>& s) { int n = s.size(); for(int left = 0,right = n-1;left <= right;left++,right--){ swap(
半生瓜的blog
2023/05/13
2100
【代码随想录】二刷-字符串
字符串:简单的反转还不够!
给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。
代码随想录
2020/09/02
5480
leetcode-翻转字符串里的单词
输入: " hello world! " 输出: "world! hello"
早起的鸟儿有虫吃
2019/05/05
8370
leetcode-翻转字符串里的单词
继续反转字符串
https://leetcode-cn.com/problems/reverse-string-ii/
代码随想录
2021/07/16
7000
【C++】string类(附题)
C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列 的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户 自己管理,稍不留神可能还会越界访问。
ZLRRLZ
2024/12/13
1270
【C++】string类(附题)
LeetCode 151. 翻转字符串里的单词(栈)
无空格字符构成一个单词。 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
Michael阿明
2021/02/20
3890
LeetCode 151. 翻转字符串里的单词(栈)
字符串:总结篇!
其实我们已经学习了十天的字符串了,从字符串的定义到库函数的使用原则,从各种反转到KMP算法,相信大家应该对字符串有比较深刻的认识了。
代码随想录
2020/09/11
5260
151. 翻转字符串里的单词
reverse-words-in-a-string 一、描述 151. 翻转字符串里的单词 给定一个字符串,逐个翻转字符串中的每个单词。 说明: 无空格字符构成一个单词。 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 进阶: 请选用 C 语言的用户尝试使 ,意思是说原地反转。 输入: " hello world! " 输出: "world! hello" 解释: 输入字符串可以在前面或者后面包含多余的空格,但
早起的鸟儿有虫吃
2020/07/02
9510
151. 翻转字符串里的单词
557. 反转字符串中的单词 III
给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。
韩旭051
2020/09/01
1.4K0
leetcode-151-翻转字符串里的单词
1、这道题给定一个字符串s,相当于一个英文句子,要求把这个句子中的单词反转一下,后面的要放在前面,前面放在后面。
chenjx85
2018/09/29
1.9K0
【C++】9道经典面试题带你玩转string类
https://leetcode.cn/problems/ba-zi-fu-chuan-zhuan-huan-cheng-zheng-shu-lcof/
修修修也
2024/06/17
1300
【C++】9道经典面试题带你玩转string类
《代码随想录》笔记
O(1)常数阶 < O( log n)对数阶 < O(n)线性阶 < O(n log n)线性对数阶 < O(n^2)平方阶 < O(n^3)立方阶 < O(2^n)指数阶
LucianaiB
2025/05/28
1060
关于字符串,我总结了这些
从字符串的定义到库函数的使用原则,从各种反转到KMP算法,相信大家应该对字符串有比较深刻的认识了。
代码随想录
2021/07/16
4280
字符串:替换空格
示例 1: 输入:s = "We are happy." 输出:"We%20are%20happy."
代码随想录
2020/09/10
5.1K0
字符串:替换空格
算法思想总结:字符串
思路1:两两比较 时间复杂度mn 实现findcomon返回两两比较后的公共前缀
小陈在拼命
2024/07/16
1050
算法思想总结:字符串
c++:string相关的oj题(415. 字符串相加、125. 验证回文串、541. 反转字符串 II、557. 反转字符串中的单词 III)
利用每次要跳2k来处理:就直接i+=2k,这样每次直接跳到下一个区间,前面够2k的不用管,直接满足i+k<=len,只有那最后一个不够2k的需要讨论(毕竟s.begin()+len是最后元素的下个位置)
是Nero哦
2024/01/24
1720
c++:string相关的oj题(415. 字符串相加、125. 验证回文串、541. 反转字符串 II、557. 反转字符串中的单词 III)
反转字符串还有这个用处?
https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/
代码随想录
2021/07/16
4170
【代码随想录】二刷-双指针法
双指针 27. 移除元素 // 时间复杂度 O(n) // 空间复杂度 O(1) class Solution { public: int removeElement(vector<int>& nums, int val) { int slow = 0; int fast = 0; int n = nums.size(); while(fast < n){ if(nums[fast] != val){
半生瓜的blog
2023/05/13
1620
​LeetCode刷题实战541:反转字符串 II
算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !
程序员小猿
2022/03/03
2430
相关推荐
这次我们翻转字符串里的单词
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验