31
31
32
32
# 思路
33
33
34
- ** 这道题目可以说是综合考察了字符串的多种操作。 **
34
+ 针对本题,我录制了视频讲解: [ 字符串复杂操作拿捏了! | LeetCode:151.翻转字符串里的单词 ] ( https://www.bilibili.com/video/BV1uT41177fX ) ,结合本题解一起看,事半功倍!
35
35
36
+ ** 这道题目可以说是综合考察了字符串的多种操作。**
36
37
37
38
一些同学会使用split库函数,分隔单词,然后定义一个新的string字符串,最后再把单词倒序相加,那么这道题题目就是一道水题了,失去了它的意义。
38
39
@@ -81,17 +82,14 @@ void removeExtraSpaces(string& s) {
81
82
82
83
如果不仔细琢磨一下erase的时间复杂度,还以为以上的代码是O(n)的时间复杂度呢。
83
84
84
- 想一下真正的时间复杂度是多少,一个erase本来就是O(n)的操作,erase实现原理题目:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html),最优的算法来移除元素也要O(n) 。
85
+ 想一下真正的时间复杂度是多少,一个erase本来就是O(n)的操作。
85
86
86
87
erase操作上面还套了一个for循环,那么以上代码移除冗余空格的代码时间复杂度为O(n^2)。
87
88
88
89
那么使用双指针法来去移除空格,最后resize(重新设置)一下字符串的大小,就可以做到O(n)的时间复杂度。
89
90
90
- 如果对这个操作比较生疏了,可以再看一下这篇文章:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html)是如何移除元素的。
91
-
92
- 那么使用双指针来移除冗余空格代码如下: fastIndex走的快,slowIndex走的慢,最后slowIndex就标记着移除多余空格后新字符串的长度。
93
-
94
91
```CPP
92
+ //版本一
95
93
void removeExtraSpaces(string& s) {
96
94
int slowIndex = 0, fastIndex = 0; // 定义快指针,慢指针
97
95
// 去掉字符串前面的空格
@@ -121,120 +119,58 @@ void removeExtraSpaces(string& s) {
121
119
1 . leetcode上的测试集里,字符串的长度不够长,如果足够长,性能差距会非常明显。
122
120
2 . leetcode的测程序耗时不是很准确的。
123
121
124
- 此时我们已经实现了removeExtraSpaces函数来移除冗余空格。
122
+ 版本一的代码是比较如何一般思考过程,就是 先移除字符串钱的空格,在移除中间的,在移除后面部分。
125
123
126
- 还做实现反转字符串的功能,支持反转字符串子区间,这个实现我们分别在 [ 344.反转字符串 ] ( https://programmercarl.com/0344.反转字符串 .html ) 和 [ 541.反转字符串II ] ( https://programmercarl.com/0541.反转字符串II.html ) 里已经讲过了。
124
+ 不过其实还可以优化,这部分和 [ 27.移除元素 ] ( https://programmercarl.com/0027.移除元素 .html ) 的逻辑是一样一样的,本题是移除空格,而 27.移除元素 就是移除元素。
127
125
128
- 代码如下 :
126
+ 所以代码可以写的很精简,大家可以看 如下 代码 removeExtraSpaces 函数的实现 :
129
127
130
- ```
131
- // 反转字符串s中左闭又闭的区间[start, end]
132
- void reverse(string& s, int start, int end) {
133
- for (int i = start, j = end; i < j; i++, j--) {
134
- swap(s[i], s[j]);
128
+ ``` CPP
129
+ // 版本二
130
+ void removeExtraSpaces (string& s) {//去除所有空格并在相邻单词之间添加空格, 快慢指针。
131
+ int slow = 0; //整体思想参考https://programmercarl.com/0027.移除元素.html
132
+ for (int i = 0; i < s.size(); ++i) { //
133
+ if (s[ i] != ' ') { //遇到非空格就处理,即删除所有空格。
134
+ if (slow != 0) s[ slow++] = ' '; //手动控制空格,给单词之间添加空格。slow != 0说明不是第一个单词,需要在单词前添加空格。
135
+ while (i < s.size() && s[ i] != ' ') { //补上该单词,遇到空格说明单词结束。
136
+ s[ slow++] = s[ i++] ;
137
+ }
138
+ }
135
139
}
140
+ s.resize(slow); //slow的大小即为去除多余空格后的大小。
136
141
}
137
142
```
138
143
139
- 本题C++整体代码
144
+ 如果以上代码看不懂,建议先把 [27.移除元素](https://programmercarl.com/0027.移除元素.html)这道题目做了,或者看视频讲解:[数组中移除元素并不容易!LeetCode:27. 移除元素](https://www.bilibili.com/video/BV12A4y1Z7LP) 。
140
145
146
+ 此时我们已经实现了removeExtraSpaces函数来移除冗余空格。
141
147
142
- ``` CPP
143
- // 版本一
144
- class Solution {
145
- public:
146
- // 反转字符串s中左闭又闭的区间[ start, end]
147
- void reverse(string& s, int start, int end) {
148
- for (int i = start, j = end; i < j; i++, j--) {
149
- swap(s[ i] , s[ j] );
150
- }
151
- }
148
+ 还做实现反转字符串的功能,支持反转字符串子区间,这个实现我们分别在[344.反转字符串](https://programmercarl.com/0344.反转字符串.html)和[541.反转字符串II](https://programmercarl.com/0541.反转字符串II.html)里已经讲过了。
152
149
153
- // 移除冗余空格:使用双指针(快慢指针法)O(n)的算法
154
- void removeExtraSpaces(string& s) {
155
- int slowIndex = 0, fastIndex = 0; // 定义快指针,慢指针
156
- // 去掉字符串前面的空格
157
- while (s.size() > 0 && fastIndex < s.size() && s[fastIndex] == ' ') {
158
- fastIndex++;
159
- }
160
- for (; fastIndex < s.size(); fastIndex++) {
161
- // 去掉字符串中间部分的冗余空格
162
- if (fastIndex - 1 > 0
163
- && s[fastIndex - 1] == s[fastIndex]
164
- && s[fastIndex] == ' ') {
165
- continue;
166
- } else {
167
- s[slowIndex++] = s[fastIndex];
168
- }
169
- }
170
- if (slowIndex - 1 > 0 && s[slowIndex - 1] == ' ') { // 去掉字符串末尾的空格
171
- s.resize(slowIndex - 1);
172
- } else {
173
- s.resize(slowIndex); // 重新设置字符串大小
174
- }
175
- }
150
+ 代码如下:
176
151
177
- string reverseWords(string s) {
178
- removeExtraSpaces (s); // 去掉冗余空格
179
- reverse(s, 0, s.size() - 1); // 将字符串全部反转
180
- int start = 0; // 反转的单词在字符串里起始位置
181
- int end = 0; // 反转的单词在字符串里终止位置
182
- bool entry = false; // 标记枚举字符串的过程中是否已经进入了单词区间
183
- for (int i = 0; i < s.size(); i++) { // 开始反转单词
184
- if (!entry) {
185
- start = i; // 确定单词起始位置
186
- entry = true; // 进入单词区间
187
- }
188
- // 单词后面有空格的情况,空格就是分词符
189
- if (entry && s[ i] == ' ' && s[ i - 1] != ' ') {
190
- end = i - 1; // 确定单词终止位置
191
- entry = false; // 结束单词区间
192
- reverse(s, start, end);
193
- }
194
- // 最后一个结尾单词之后没有空格的情况
195
- if (entry && (i == (s.size() - 1)) && s[ i] != ' ' ) {
196
- end = i;// 确定单词终止位置
197
- entry = false; // 结束单词区间
198
- reverse(s, start, end);
199
- }
200
- }
201
- return s;
202
- }
203
-
204
- // 当然这里的主函数reverseWords写的有一些冗余的,可以精简一些,精简之后的主函数为:
205
- /* 主函数简单写法
206
- string reverseWords(string s) {
207
- removeExtraSpaces(s);
208
- reverse(s, 0, s.size() - 1);
209
- for(int i = 0; i < s.size(); i++) {
210
- int j = i;
211
- // 查找单词间的空格,翻转单词
212
- while(j < s.size() && s[ j] != ' ') j++;
213
- reverse(s, i, j - 1);
214
- i = j;
215
- }
216
- return s;
152
+ ```CPP
153
+ // 反转字符串s中左闭又闭的区间[start, end]
154
+ void reverse(string& s, int start, int end) {
155
+ for (int i = start, j = end; i < j; i++, j--) {
156
+ swap(s[i], s[j]);
217
157
}
218
- * /
219
- };
158
+ }
220
159
```
221
160
222
- 效率:
223
- <img src =' https://code-thinking.cdn.bcebos.com/pics/151_翻转字符串里的单词.png ' width =600 > </img ></div >
161
+ 整体代码如下:
224
162
225
163
``` CPP
226
- // 版本二:
227
- // 原理同版本1,更简洁实现。
228
164
class Solution {
229
165
public:
230
- void reverse(string& s, int start, int end){ //翻转,区间写法:闭区间 [ ]
166
+ void reverse(string& s, int start, int end){ //翻转,区间写法:左闭又闭 [ ]
231
167
for (int i = start, j = end; i < j; i++, j--) {
232
168
swap(s[ i] , s[ j] );
233
169
}
234
170
}
235
171
236
172
void removeExtraSpaces(string& s) {//去除所有空格并在相邻单词之间添加空格, 快慢指针。
237
- int slow = 0; //整体思想参考Leetcode: 27. 移除元素:https://leetcode.cn/problems/remove-element/
173
+ int slow = 0; //整体思想参考https://programmercarl.com/0027.移除元素.html
238
174
for (int i = 0; i < s.size(); ++i) { //
239
175
if (s[i] != ' ') { //遇到非空格就处理,即删除所有空格。
240
176
if (slow != 0) s[slow++] = ' '; //手动控制空格,给单词之间添加空格。slow != 0说明不是第一个单词,需要在单词前添加空格。
@@ -261,6 +197,7 @@ public:
261
197
};
262
198
```
263
199
200
+
264
201
## 其他语言版本
265
202
266
203
0 commit comments