目录
344.反转字符串
题目链接
(1)文字讲解:https://programmercarl.com/0344.反转字符串.html
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/reverse-string/
看到题解之前的想法
不会写
看到题解之后的想法
因为字符串的存储方式本质是数组,所以可以利用双指针法,从开头和末尾出发,交换开头和末尾的元素,一直到字符串的中点就可以了。
本题难点
代码
class Solution {
public:
void reverseString(vector<char>& s) {
for (int i = 0, j = s.size()-1; i < s.size()/2; i++,j--){
swap(s[i], s[j]);
}
}
};
541. 反转字符串II
题目链接
(1)文字讲解:https://programmercarl.com/0541.反转字符串II.html
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/reverse-string-ii/description/
看到题解之前的想法
其实就是一个模拟题。写一个函数,输入start和end,使其能够只反转字符串中start到end这一段。然后遍历字符串,每当i能够整除2k的时候,就说明要反转前面一段了,那么就调用函数。退出遍历后,检查剩下的字符串长度(s.length()%2k),按照题目的要求输入反转范围,调用函数就行。
看到题解之后的想法
1.i可以每次都加2k,这样更加方便
2.其实剩下的res只要大于k,那么都是反转前k个数,那么其实可以不用单独处理res,只需要判断当前的i+k是否小于字符串长度,小于的话就反转这一段的前k个;如果已经大于,说明res不足k个,全部反转。
本题难点
for循环中i每次可以➕任意数值
代码
我写的:
class Solution {
public:
void reverseSection(int start, int end, string& s){
for(int p = start, q = end; p < (end-start+1)/2+start; p++, q--){
char tmp = s[p];
s[p] = s[q];
s[q] = tmp;
}
}
string reverseStr(string s, int k) {
int res = s.length()%(2*k);
for(int i = 0; i < s.length(); i++){
if((i+1)%(2*k)==0){
reverseSection(i+1-2*k, i-k, s);
}
}
if(res < k){
reverseSection(s.length()-res, s.length()-1, s);
}else{
reverseSection(s.length()-res, s.length()-1-res+k, s);
}
return s;
}
};
题解写的:
class Solution {
public:
string reverseStr(string s, int k) {
for(int i = 0; i < s.length(); i += 2*k){
if(i+k < s.length()){
reverse(s.begin()+i, s.begin()+i+k);
}else{
reverse(s.begin()+i, s.end());
}
}
return s;
}
};
151.翻转字符串里的单词
题目链接
(1)文字讲解:https://programmercarl.com/0151.翻转字符串里的单词.html
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/reverse-words-in-a-string/submissions/509791046/
看到题解之前的想法
不会写
看到题解之后的想法
模拟题,但是需要灵活一点:
1.首先将多余的空格去掉
2.再将整个句子反转过来
3.再将单个单词反转过来
去掉多余的空格,其实有点像27.移除元素,只不过这里的元素变成了空格。而且还需要注意,不能够全都移除,要给每个单词之间留下一个空格,所以才有
if(slow != 0){
s[slow++] = ' ';
}
同时,因为只能在单词间加入空格,所以要在加完空格后录入整个单词,不然for循环会让每个字母后都加入一个空格:
while(fast < s.length() && s[fast] != ' '){
s[slow++] = s[fast++];
}
去除空格后,再写一个反转指定区间的字符串的函数就可以了。
本题难点
将去除空格看作去除重复元素,使用双指针法,而不是用erase函数(时间复杂度为O(n^2))。
代码
class Solution {
public:
void removeExtraSpace(string& s){
int slow = 0;
for(int fast = 0; fast < s.length(); fast++){
if(s[fast] != ' '){
if(slow != 0){
s[slow++] = ' ';
}
while(fast < s.length() && s[fast] != ' '){
s[slow++] = s[fast++];
}
}
}
s.resize(slow);
}
void reverseSection(int start, int end, string& s){
for(int p = start, q = end; p < q; p++, q--){
char tmp = s[p];
s[p] = s[q];
s[q] = tmp;
}
}
string reverseWords(string s) {
removeExtraSpace(s);
reverseSection(0, s.length()-1, s);
int wordStart = 0;
for(int i = 0; i < s.length(); i++){
if(s[i]==' '){
reverseSection(wordStart, i-1, s);
wordStart = i+1;
}else if(i == s.length()-1){
reverseSection(wordStart, i, s);
wordStart = s.length();
}
}
return s;
}
};
替换数字
题目链接
(1)文字讲解:https://programmercarl.com/kama54.替换数字.html#思路
(2)视频讲解:
(3)题目链接:https://kamacoder.com/problempage.php?pid=1064
看到题解之前的想法
现在看到替换就会想到双指针,但是这一题,因为是将单个数字换成长度为6的单词‘number’,所以如果按照以往的快慢指针替换思路,不添加额外的操作空间,slow指针会很快追上fast指针(只要一替换number,slow就会➕6),那么新的替换过的字符串将会覆盖旧的字符串,所以我就只能想到开一个新的字符串,但是这样不够简洁。
看到题解之后的想法
依然是双指针,但是是从后往前的双指针。
看图:
这样就可以保证新的字符串不会覆盖原来的字符串了。
本题难点
1.c++中不可以用’0’<= s[i] <= ‘9’, 必须用’0’<= s[i] && s[i] <= ‘9’
2.string在c++中可以使用resize函数重新分配大小
3.双指针如果知道替换之后的字符串或者数组大小,可以倒着用。
4.卡码网是c++格式的,就是说需要自己写引入什么包以及main函数体,有时候面试的时候会让你写出输入输出,有必要加强。
代码
# include<iostream>
using namespace std;
const int length = 60000;
int main(){
string s;
while(cin>>s){
int count = 0;
int ori_length = s.length();
for(int i = 0; i < s.length(); i++){
if(s[i] >= '0' && s[i] <= '9'){
count++;
}
}
s.resize(s.length()+count*5);
int fast = s.length()-1;
for(int slow = ori_length-1; slow >= 0; slow--){
if('0' <= s[slow] && s[slow] <= '9'){
s[fast] = 'r';
s[fast-1] = 'e';
s[fast-2] = 'b';
s[fast-3] = 'm';
s[fast-4] = 'u';
s[fast-5] = 'n';
fast -= 5;
}else{
s[fast] = s[slow];
}
fast--;
}
cout<<s<<endl;
}
return 0;
}
右旋字符串
题目链接
(1)文字讲解:https://programmercarl.com/kama55.右旋字符串.html
(2)视频讲解:
(3)题目链接:https://kamacoder.com/problempage.php?pid=1065
看到题解之前的想法
不会写
看到题解之后的想法
这个其实和151.翻转字符串里的单词是一样的思路。以n为界限,将字符串分为两段,然后整体反转字符串,再局部反转这两段,就行了(相当于之前的先反转整段再反转单词)
本题难点
1.c++中reverse函数需要# include
2.c++中reverse函数反转的是[start, end)这个左闭右开区间
3.字符串的begin和end函数,begin指向的是字符串的开头,而end是结尾➕1。
4.剑指offer里面有一个字符串左转,其实和这个一样的思路,就是区间不一样。
代码
先反转局部再反转整体
# include<iostream>
# include<algorithm>
using namespace std;
int main(){
string s;
int n;
cin>>n;
cin>>s;
int len = s.size();
reverse(s.begin(), s.begin()+len-n);
reverse(s.begin()+len-n, s.end());
reverse(s.begin(), s.end());
cout<<s<<endl;
return 0;
}
先整体再局部:
# include<iostream>
# include<algorithm>
using namespace std;
int main(){
string s;
int n;
cin>>n;
cin>>s;
int len = s.size();
reverse(s.begin(), s.end());
reverse(s.begin(), s.begin()+n);
reverse(s.begin()+n, s.end());
cout<<s<<endl;
return 0;
}