ch4_4 反转字符串中的单词
给你一个字符串 s ,颠倒字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
4.1 分析
C++ 语言中, 字符串是可变的:
-
去重三种情况下的空格
-
将整个字符串反转;
-
将每个单词反转;
整体逻辑框架
#include "string"
using namespace std;
class Solution{
public:
void removeExtraSpace(string& s){
}
void reverseString(string& s, int start, int end){
}
string reverseWords(string s){
// 1. 移除多余空格
removeExtraSpace(s);
// 2. 反转字符串;
reverseString(s, 0, s.size());
// 遍历字符串, 反转每个单词,
for(int i = 0; i < s.size(); i++){
int seg = i; // 当前位置作为单词的首个字符;
// 使用空格作为标志,找出每个单词; 循环结束后, seg 到达该单词后的空格位置上;
while (seg < s.size() && s[seg] != ' ') seg++;
reverseString(s, i, seg-1);
// 将下一个 i 的起始位置更新为 空格处开始;
i = seg;
}
return s;
}
};
4.2 去重三种情况下的空格
-
开头位置空格;
先通过fastindex 走到开始 非空格的起始位置, 去除开头空; -
单词之间冗余空格的去除,(正常只有一个空格, 多于一个空格即为冗余空格);
循环遍历字符串数组的过程中,
如果是冗余空格,则将冗余空格去除;
如果非冗余空格, 将 fastIndex 赋值给 slowIndex -
去重字符串末尾的空格, 并重置整个字符串的大小为slowindex;
void removeExtraSpaces(string& s) {
int slowIndex = 0, fastIndex = 0; // 定义快指针,慢指针
// 去掉字符串前面的空格
while (s.size() > 0 && fastIndex < s.size() && s[fastIndex] == ' ') {
fastIndex++; // fastindex 走到初始不是空格的位置处;
}
for (; fastIndex < s.size(); fastIndex++) {
// 去掉字符串中间部分的冗余空格, 通过跳过双重空格;
if (fastIndex - 1 > 0 && s[fastIndex - 1] == s[fastIndex] && s[fastIndex] == ' ') {
continue;
} else { // 开始将fastIndex 去重后的字符赋值给 slowIndex;
s[slowIndex++] = s[fastIndex];
}
}
// 若果 slowIndex 最后一个位置被赋值为空格, 将其去除;
if (slowIndex - 1 > 0 && s[slowIndex - 1] == ' ') { // 去掉字符串末尾的空格
s.resize(slowIndex - 1);
} else {
s.resize(slowIndex); // 重新设置字符串大小
}
}
4.3 将给定区间字符串反转;
void reverseString(string& s , int start, int end){
for(int i = start, j = end; i <j; i++,j--)
swap(s[i], s[j]);
}
4.4 将每个单词反转;
找出每个单词的区间,以空格为单词区间标志;
然后使用反转函数;
for(int i = 0; i < s.size(); i++){
int seg = i;
// 将seg 移动到该单词结束后的一个空格位置上;
while( seg < s.size() && s[seg] != ' ') seg++;
// 经过上述循环后,到达每个单词结束后的空格位置上;
reverse(s, i, seg - 1);
// 将i 赋值为 空格位置, 继续下一轮循环;
i = seg;
4.5 完整code
#include "string"
using namespace std;
class Solution{
public:
void removeExtraSpace(string& s){
int slowIndex = 0, fastIndex = 0;
// 1. 去除开头空格, 先让fastIndex 走到非空格处;
while( s.size() > 0 && fastIndex < s.size() && s[fastIndex] == ' ') {fastIndex++;}
// 从非空格处的地方开始,遍历字符串数组;
for(; fastIndex < s.size(); fastIndex++) {
// 2. 排除开头位置的, 找到单词之间的冗余空格;
if (fastIndex - 1 > 0 && s[fastIndex] == s[fastIndex - 1] && s[fastIndex] == ' ')
continue; // 跳过单词之间,超过一个空格的部分;
else{ s[slowIndex++] = s[fastIndex]; } // 将fastIndex 位置上的字符 赋值给 slowIndex
}
//注意由于,上面赋值为 slowIndex++, 所以此时串的长度是 slowIndex, 而最后一个位置的下标是slowIndex - 1
// 3. 开始移除末尾的空格; 如果最后一个位置是空格, 并且该空格不是第一个位置;
if(s[slowIndex -1] == ' ' && slowIndex - 1 > 0) s.resize(slowIndex -1);
else{ s.resize(slowIndex); // 如果末尾 是非空格,则将字符串大小重置为slowIndex;
}
}
void reverseString(string& s, int start, int end){
for(int i = start, j = end; i < j; i++,j--){
swap(s[i], s[j]);
}
}
string reverseWords(string s){
// 1. 去除空格;
removeExtraSpace(s);
// 2. 反转字符串;
reverseString(s, 0, s.size()-1);
// 3. 找出每个单词,以 空格为 标志, 对每个单词进行反转,
for(int i = 0; i < s.size(); i++){
int seg = i;
while(seg< s.size() && s[seg] != ' ') seg++;
// 循环结束后, 找到了每个单词的结束后对应的空格位置; 将该区间反转;
reverseString(s, i, seg -1);
i = seg; // 下一轮循环, i 从另一个单词开始;
}
return s;
}
};
ch4_5. 左转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
2.1 解题步骤
- 反转区间 0- n 的子串;
- 反转区间 n ~ 末尾的子串;
- 反转整个字符串;
#include "string"
using namespace std;
class Solution{
public:
void reverseString(string& s, int start, int end ){
for(int i = start, j = end; i <j; i++,j--)
swap(s[i], s[j]);
}
string reverseLeftWords(string s, int n){
reverseString(s, 0, n - 1);
reverseString(s,n , s.size() - 1);
reverseString(s, 0, s.size() -1);
return s;
}
};