简单题,直接手撕或者函数都可以
双指针法,左右指针,切换
class Solution {
public:
void reverseString(vector<char>& s) {
int left = 0;
int right = s.size()-1;
while(left <= right){
char leftChar = s[left];
char rightChar = s[right];
//交换
char tmp = leftChar;
leftChar = rightChar;
rightChar = tmp;
s[left++] = leftChar;
s[right--] = rightChar;
}
}
};
函数 reverse()
class Solution {
public:
void reverseString(vector<char>& s) {
reverse(s.begin(),s.end());
}
};
一开始写了一堆难以名状的东西,这道模拟题不该从头遍历位置的,由于每次都是在一个2K区间里做反转,我们选择在for循环中一次跳到下一个区间的起点
class Solution {
public:
string reverseStr(string s, int k) {
for(int i = 0;i< s.size();i += 2*k){
if(i + k <= s.size()){
reverse(s.begin()+i,s.begin()+i+k);
}
if(i + k > s.size()){
reverse(s.begin()+i,s.end());
}
}
return s;
}
};
必须把我写的难以名状之物也分享出来!
class Solution {
public:
string reverseStr(string s, int k) {
int curCount = 0;
int base = 0;
int fast = 0;
for( int count = 1;count <= s.size();count++){
fast++;
curCount++;
if(curCount == k){
int offsetBase = base-0;
int offsetEnd = fast-0;
reverse(s.begin()+offsetBase,s.begin()+offsetEnd);
}
if(curCount == 2*k){
base = fast;
curCount = 0;
}
}
if(curCount < k){
int offsetBase = base-0;
int offsetEnd = fast-0;
reverse(s.begin()+offsetBase,s.begin()+offsetEnd);
}
return s;
}
};
实际上在字符串的处理中,当我们需要对一个字符串做多个区间的分段处理时,通常会遇到两种情况
- 周期性分段(起点是循环有规律分布的。比如这道题)
- 无规律分段(每一段的长度并不固定,换言之,没办法用一个循环来确定下一个起点,但无规律分段通常有分段的标志,通过这个确定起点)
卡码网里是ACM模式的写法,这题如果要写还是很简单的,判断遍历的字符的ASCII码值就行,但官方给出的题解用的是从后往前遍历的操作,也就是说,先计算数字字符的个数,然后resize()函数来扩充字符串大小,设置两个指针,双指针法,从后向前遇到数字就替换,直到头部位置结束
图源:代码随想录网站
我的解法:
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
cin>>s ;
for(int i = 0;i< s.size();i++){
if(int(s[i]) < 65){
cout<<"number";
}else{
cout<<s[i];
}
}
return 0;
}
字符串的分段反转,和我上面说的一样,这是一道区间长度不固定的分段反转,而且用于区分段间的标志也有重复的可能,思路是先用双指针法,类似于数组的移除元素,把空格字符全部去掉,这样,前置,后置,段间的空格就全部移除了,但是段间是要留一个空格的,那么我们每次都删除空格以后再补一个做分段标志。
随后就是整体反转,然后对应各区间分段反转,就达成区间位置改变,而区间内不变的操作了
class Solution {
public:
string reverseWords(string s) {
//移除空格
int slow = -1;
int blankcount = 1;
for(int fast = 0;fast < s.size();fast++){
if(s[fast] != ' '){
if(slow != -1 && fast-1 >= 0 && s[fast] != ' ' && s[fast-1] == ' '){
s[++slow] = ' ';
}
s[++slow] = s[fast];
}
}
s.resize(slow+1);
//整体反转
reverse(s.begin(),s.end());
//分组反转
int base = 0;
for(int i = 0;i< s.size();i++){
if(s[i] == ' ' ){
reverse(s.begin()+base,s.begin()+i);
base = i+1;
}
if(i + 1 == s.size()){
reverse(s.begin()+base,s.end());
}
}
return s;
}
};
我一开始的解法里用了栈来存各个区间的数据,并没有达成算法原地工作的空间复杂度,不太好
class Solution {
public:
string reverseWords(string s) {
string res = "";
stack<string> reverseStack;
int index = 0;
while(index < s.size()){
if(res.size() == 0){
if(s[index] != ' '){
res.push_back(s[index]);
}
index++;
continue;
}
if(s[index] != ' '){
res.push_back(s[index]);
index++;
if(index == s.size()){
reverseStack.push(res);
res = "";
}
continue;
}
reverseStack.push(res);
res = "";
}
if(res != ""){
reverseStack.push(res);
res = "";
}
while(!reverseStack.empty()){
res.append(reverseStack.top());
res.append(" ");
reverseStack.pop();
}
res.pop_back();
return res;
}
};
这道题相对简单,相当于是反转字符串中单词的简单版,区间不定,但是给出对应的区间起点(起点也不重复),无需自己遍历查找
先整体反转,再各个区间单独反转就行
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main(){
int k;
string s;
cin>> k;
cin>> s;
reverse(s.begin(),s.end());
reverse(s.begin(),s.begin()+k);
reverse(s.begin()+k,s.end());
cout<<s;
return 0;
}
移除字符串中的元素,也是用双指针法,和数组的移除元素操作类似,字符串的替换可以考虑双指针法分别从后遍历新旧空间来处理,字符串分区间反转问题也需要注意