【字符串1】344.反转字符串 541. 反转字符串II 151.翻转字符串里的单词 替换数字 右旋字符串

文章讲述了如何使用双指针技巧解决LeetCode中的四个字符串操作问题:反转字符串、反转字符串II、翻转字符串里的单词和替换数字,包括理解题意、实现策略和代码示例。
摘要由CSDN通过智能技术生成

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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值