第八天打卡(字符串)

文章讲述了在LeetCode上的多个字符串操作题目,如反转字符串、替换数字、单词反转以及右旋字符串的解题过程,强调了不同情况下的代码实现和优化策略,特别是空间复杂度为O(1)的解决方案。
摘要由CSDN通过智能技术生成

一、反转字符串

1、力扣题目

题目链接:344. 反转字符串 - 力扣(LeetCode)(该题建议手动实现反转

2、初次解题

有两个思路

第一个是直接用c++中string自带的反转函数

代码如下:

class Solution {
public:
    void reverseString(vector<char>& s) {
        reverse(s.begin(),s.end());//反转函数
    }
};

第二个是手动实现反转,用双指针,两两交换

代码如下:

class Solution {
public:
    void reverseString(vector<char>& s) {
        int left=0;
        int right=s.size()-1;
        while(left<right){
            char a=s[left];
            s[left]=s[right];
            s[right]=a;
            left++;
            right--;
        }
    }
};

3、视频学习

视频链接:字符串基础操作! | LeetCode:344.反转字符串_哔哩哔哩_bilibili

简单看了一下,跟视频跟上述思路差不多,就不再赘述。不过他在交换时用到了swap函数,上述代码中swap也手动实现了。

二、反转字符串

1、力扣题目

题目链接:541. 反转字符串 II - 力扣(LeetCode)

2、初次解题

因为刚开始用c++,所以对一些函数的确切用法没有仔细了解,在c++的reverse中是前闭后开区间,导致想了半天,应多留意函数的使用规则。

s.begin()指向第一个元素,s.end()指向最后一个元素的后面。

对于一些分组求的情况,i 每次增加一组的量,这样可以保证分组进行处理。

不过刚开始我对剩余数目大于2k,大于k小于2k,小于k三种情况都分别进行了讨论,不过后面发现后两种情况可以合并。

class Solution {
public:
    string reverseStr(string s, int k) {
        for(int i=0;i<s.size();i+=2*k){//分组处理
            int last=s.size()-i-1;//首先判断剩余字符数
            if(last<k){//比k小,反转剩下全部
                reverse(s.begin()+i,s.end());
                break;
            }
            else{
                reverse(s.begin()+i,s.begin()+i+k);//应该是i+k,因为是下标[i,i+k)包括i的k个
            }
        }
        return s;
    }
};

3、视频学习

视频链接:字符串操作进阶! | LeetCode:541. 反转字符串II_哔哩哔哩_bilibili

本质思路差不多,有需要的可以看一下

4、总结

刚开始想的时候有点偏了,遍历的时候i++,想着怎么确定2k个字符,后面才反应过来i+=2k就行了,下次应该注意这种分组处理的情况。

三、替换数字

1、卡码网题目

题目链接:54. 替换数字(第八期模拟笔试) (kamacoder.com)

2、初次解题

看完题目想的就是直接再定义一个string作为输出结果,处理的时候字符链接就行。

代码如下:

#include<iostream>
#include<string>
 
using namespace std;
int main(){
    string a;
    cin >>  a;
    string b;
    for(int i=0;i<a.size();i++){
        if(a[i]-'a'>=0&&'z'-a[i]>=0){b+=a[i];}
        else{
            b+="number";//注意是双引号
        }
    }
   cout << b << endl;
     
}

3、文章学习

上述思路利用了另一个字符串,要是空间复杂度为O(1)的话,那么就需要首先遍历一遍字符串,统计一下数字出现的次数,然后s.resize(s.size()+count*5),此处需注意是*5,因为"number"中有一个字母占据数字的位置,所以另外需要的空间大小就是5。

然后进行倒序遍历,代码我就不写了,就思路理解一下吧。

如下图所示,图片来自代码随想录:

4、总结

注意单引号是字符,双引号是字符串。然后理解空间复杂度为O(1)的解法,注意倒序遍历。

四、反转字符串的字母

1、力扣题目

题目链接:151. 反转字符串中的单词 - 力扣(LeetCode)

2、初次解题

想法是对先整个字符串进行反转,然后再对单个单词进行反转,最后删除空格

单词反转思路:

1、在原字符串末尾增加一个空格

2、使用双指针,指向单词开头第一个字母,right指向单词后的第一个空格。reverse(left,right)之后left=right。

3、为了确保left指向第一个字母,当left指向空格时,left++后跳转下一次循环

因为最后一个字符一定为空,所以最后一次left一定在left++,因而循环条件为left<s.size(),最后可以跳出循环且完成了遍历。

删除空格思路:

如果当前和前一个相等且都为空格,则从删除当前元素,之后判断首位是否为空,是则删除首位空格,最后删除末尾的空格。

代码如下:

class Solution {
public:
    string reverseWords(string s) {
        reverse(s.begin(),s.end());//反转字符串

        s+=' ';//便于后续操作

        //左右指针
        int left=0;//单词开头第一个字母
        int right=0;//单词最后一个字母

        while(left<s.size()){
            if(s[left]==' '){left++;continue;}
            right=left;//第一个不为空格的

            while(s[right]!=' ')right++;
            reverse(s.begin()+left,s.begin()+right);  //反转单词

            left=right;     
        }

        //使用迭代器遍历删除
        string::iterator itr=next(s.begin());
        while(itr!=s.end()){
            if(*itr==' '&&*prev(itr)==' '){
                s.erase(itr);
                continue;
            }
            itr++;
        }
        if(*s.begin()==' ')s.erase(s.begin());
        s.erase(s.end()-1);
        return s;
    }
};

3、视频学习

视频链接:字符串复杂操作拿捏了! | LeetCode:151.翻转字符串里的单词_哔哩哔哩_bilibili

大致思路跟上述一下一致,不过视频是先删除的空格,然后再处理单个单词的时候。此处主要是删除空格的方法的改进。

使用双指针,一个快,一个慢。快指针遍历字符串,仅当指向字母时进行处理,这里相当于删除了所有空格。

慢指针在单词前手动添加一个空格(首单词除外)即可。

这里仅给出双指针删除的代码:

        //双指针删除,快慢指针
        int slow = 0;
        for (int fast = 0; fast < s.size(); fast++) { 
            //遇到非空格就处理,即删除所有空格
            if (s[fast]!=' ') { //(fast代表所有单词,不含空格)

                //给单词之间添加空格,除了第一个单词,其余都需要在单词前添加空格。
                if (slow != 0){
                    s[slow]=' '; 
                    slow++;
                }

                //单词复制,遇到空格说明单词结束。
                while (fast < s.size() && s[fast] != ' ') {
                    s[slow]=s[fast];
                    fast++;
                    slow++;
                }
            }
        }
        s.resize(slow); //去除多余空格。

4、总结

反转的时候用双指针,到删除的时候就没想起来,应注意当在数组更新时,可以考虑使用快慢指针。

五、右旋字符串

1、卡码网习题

题目链接:55. 右旋字符串(第八期模拟笔试) (kamacoder.com)

2、初次解题

可能是因为上一题连着写,所以突然注意到,将整个字符串反转过来,然后再分段进行反转,就可以得到答案。

代码如下:

#include<iostream>
#include<string>
#include <algorithm>  
using namespace std;
int main(){
    int n;
    string a;
    cin >> n;
    cin >> a;
    reverse(a.begin(),a.end());//整体反转
    
    reverse(a.begin(),a.begin()+n);//反转前n个
    reverse(a.begin()+n,a.end());//反转剩余字符
    
    scout << a;
}

3、文章学习

看了一下思路,跟上述一样。如果是左旋转的话,其实就是右旋( s.size() - n )。

六、总结

单解题的话难度其实不大,但是注意优化的思路,空间复杂度为O(1)的解题思路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值