力扣151 反转字符串中的单词
题目链接/文章讲解/视频讲解:代码随想录
思路:这道题可以分为几个小步骤解决,首先删掉额外的空格,可以依次删除开头的空格,中间多余的空格,结尾的空格。更简单的方法是遇到空格就删掉,再在除了第一个单词以外,每个单词前面添加一个空格。其次反转所有元素,然后以空格为标志反转每一个单词。
class Solution {
public:
void reverse(string &s, int start, int end){
for(int i = start, j = end; i < j; i++, j--){
swap(s[i],s[j]);
}
}
void reverseExtraSpace(string &s){
int slow = 0;
for(int i = 0; i < s.size(); i++){
if(s[i] != ' '){
if(slow != 0){
s[slow++] = ' ';
}
while(i < s.size() && s[i] != ' '){
s[slow++] = s[i++];
}
}
}
s.resize(slow);
}
string reverseWords(string s) {
reverseExtraSpace(s);
reverse(s, 0, s.size() - 1);
int start = 0;
for(int i = 0; i <= s.size(); ++i){
if(s[i] == ' ' || i == s.size()){
reverse(s, start, i-1);
start = i + 1;
}
}
return s;
}
};
这里有一个小问题,通常在for循环处理数组时,i < s.size()即可,但是这里判断最后一个单词时,因为反转的end值是i-1,所以需要i的值取到s.size(),这里就要加一个等号。也可以不加等号分开写。
string reverseWords(string s) {
reverseExtraSpace(s);
reverse(s, 0, s.size() - 1);
int start = 0;
for(int i = 0; i < s.size(); ++i){
if(s[i] == ' '){
reverse(s, start, i-1);
start = i + 1;
}
if(i == s.size() - 1){
reverse(s, start, i);
}
}
return s;
}
卡码网55 右旋字符串
题目链接/文章讲解:
思路:一开始的想法是给字符串前面插入k个0,然后与末尾的k个字符交换。看讲解后,将字符串整体翻转,然后根据k值将字符串分为两段分别反转。
#include<iostream>
#include <algorithm>
using namespace std;
int main(){
int k;
string s;
cin >> k >> s;
int len = s.size();
reverse(s.begin(), s.end());
reverse(s.begin(), s.begin() + k);
reverse(s.begin() + k, s.end());
cout << s << endl;
}
这里遇到了一些问题:
1. 为什么是s.begin()+k,而不是直接用k
reverse
函数需要两个迭代器作为参数,而不是一个迭代器和一个整数。
2. 为什么第二个反转是reverse(s.begin(), s.begin() + k);而不是 reverse(s.begin(), s.begin() + k-1);
迭代器范围:在C++中,当我们使用迭代器指定一个范围时,通常遵循"左闭右开"的原则。这意味着起始迭代器指向我们想要包含的第一个元素,而结束迭代器指向我们想要包含的最后一个元素之后的位置。
reverse
函数的工作方式:reverse
函数反转[first, last)范围内的元素,其中 last 是要反转的最后一个元素之后的位置。举个例子:如果我们想反转字符串 “abcde” 的前三个字符,我们需要:
- 开始位置:指向 ‘a’(第一个字符)
- 结束位置:指向 ‘d’(第四个字符,即第三个字符之后)
在代码中体现:
s.begin()
指向第一个字符s.begin() + k
指向第 k+1 个字符,正好是我们想要反转的最后一个字符之后的位置如果我们使用
s.begin() + k-1
,那么我们实际上会少反转一个字符。例如,如果 k = 3,那么我们只会反转前两个字符,而不是前三个。