代码随想录算法训练营第八天 | LeeCode 344. 反转字符串, 541. 反转字符串II,卡码网:54.替换数字 ,151.翻转字符串里的单词 ,卡码网:55.右旋转字符串

题目链接:344. 反转字符串

class Solution
{
public:
    void reverseString(vector<char> &s)
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        int len=s.size();
        for(int i=0;i<len/2;i++){
            char tmp=s[i];
            s[i]=s[len-i-1];
            s[len-i-1]=tmp;
        }
        for(char c:s){
            cout<<c<<" ";
        }
    }
};

简单的数组反转操作,不用额外的数组空间的话可以用库函数swap。这里也没用库函数,就是简单的进行一个交换。

题目链接:541. 反转字符串 II

class Solution
{
public:
    //reverse库函数的作用是反转字符串,类似于
    //for(int i=0,int j=s.size()-1;i<j;i++,j--){ swap(s[i],s[j]); }
    //swap库函数的作用是反转数组中的两个数
    string reverseStr(string s, int k)
    {
        for(int i=0;i<s.size()-1;i+=2*k){
            if(i+k<=s.size()){
                reverse(s.begin()+i,s.begin()+i+k);
            }else{
                reverse(s.begin()+i,s.end());
            }
        }
        return s;
    }
};

这是代码随想录里面的一个简单的方法,运用了库函数reverse来进行字符串反转,时间复杂度是o(n),空间复杂度是o(1);我没想到运用库函数可以简化操作,我一开始用了两个循环的嵌套,里循环是和上一道题一样的思路,一直苦于怎么设置外循环的条件。看了解析才发现循环的条件写的很妙,我怎么没想到这么简洁的写法呢。

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

#include<bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    string s;
    string result;
    
    cin>>s;
    
    for(char c:s){
        if(c-'0'>=0&&c-'0'<=9){
            result+="number";
        }else{
            result+=c;
        }
    }
    
    for(char c:result){
        cout<<c;
    }
    
    return 0;
}

 我的代码,时间复杂度o(n),空间复杂度o(n)。创建了一个新的数组,增加了空间复杂度,简化了操作。

解答的代码:

#include<iostream>
using namespace std;
int main() {
    string s;
    while (cin >> s) {
        int count = 0; // 统计数字的个数
        int sOldSize = s.size();
        for (int i = 0; i < s.size(); i++) {
            if (s[i] >= '0' && s[i] <= '9') {
                count++;
            }
        }
        // 扩充字符串s的大小,也就是每个空格替换成"number"之后的大小
        s.resize(s.size() + count * 5);
        int sNewSize = s.size();
        // 从后先前将空格替换为"number"
        for (int i = sNewSize - 1, j = sOldSize - 1; j < i; i--, j--) {
            if (s[j] > '9' || s[j] < '0') {
                s[i] = s[j];
            } else {
                s[i] = 'r';
                s[i - 1] = 'e';
                s[i - 2] = 'b';
                s[i - 3] = 'm';
                s[i - 4] = 'u';
                s[i - 5] = 'n';
                i -= 5;
            }
        }
        cout << s << endl;
    }
}

利用resize函数扩充字符串,节省空间。移动非数字的字符到扩充后的相应位置,从后向前补number,这样子不用每次添加新元素都要把所有元素向后移动。

题目链接:151. 反转字符串中的单词

class Solution
{
public:
    string reverseWords(string s)
    {
        vector<string> result;
        string word;
        for(int i=0;i<s.size();i++){
            if(s[i]==' '){
                result.push_back(word);
                word="";
                continue;
            }
            word+=s[i];
        }
        result.push_back(word);
        string str;
        for(int i=result.size()-1;i>=0;i--){
            str+=result[i];
            if(result[i]!="")str+=" ";
        }
        str.resize(str.size()-1);
        return str;
    }
};

你们有这样稀碎的代码吗,真是缝缝又补补啊。借助了vector,空间复杂度已经好高了,但是还是勉强解题了。时间复杂度o(n),空间复杂度o(n).

下面是答案的代码:

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 removeExtraSpaces(string& s) {//去除所有空格并在相邻单词之间添加空格, 快慢指针。
        int slow = 0;   //整体思想参考https://programmercarl.com/0027.移除元素.html
        for (int i = 0; i < s.size(); ++i) { //
            if (s[i] != ' ') { //遇到非空格就处理,即删除所有空格。
                if (slow != 0) s[slow++] = ' '; //手动控制空格,给单词之间添加空格。slow != 0说明不是第一个单词,需要在单词前添加空格。
                while (i < s.size() && s[i] != ' ') { //补上该单词,遇到空格说明单词结束。
                    s[slow++] = s[i++];
                }
            }
        }
        s.resize(slow); //slow的大小即为去除多余空格后的大小。
    }

    string reverseWords(string s) {
        removeExtraSpaces(s); //去除多余空格,保证单词之间之只有一个空格,且字符串首尾没空格。
        reverse(s, 0, s.size() - 1);
        int start = 0; //removeExtraSpaces后保证第一个单词的开始下标一定是0。
        for (int i = 0; i <= s.size(); ++i) {
            if (i == s.size() || s[i] == ' ') { //到达空格或者串尾,说明一个单词结束。进行翻转。
                reverse(s, start, i - 1); //翻转,注意是左闭右闭 []的翻转。
                start = i + 1; //更新下一个单词的开始下标start
            }
        }
        return s;
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(1) 或 O(n),取决于语言中字符串是否可变

关键的地方在于去除空格,这里碰到空格就不处理,而是自己补空格。最后的resize是去掉最后面多余的空格。反转操作是先全部反转,再部分反转。

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

#include<bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int k;
    string s;

    cin >> k >> s;

    string tmp;
    for (int i = s.size() - k;i < s.size();i++) {
        tmp += s[i];
    }

    int count = s.size() - k;

    for (int i = s.size() - 1;i >= 0;i--) {
        if (count>0) {
            s[i] = s[i - k];
            count--;
        }
        else {
            s[i] = tmp[--k];
        }
    }

    for (char c : s) {
        cout << c;
    }

    return 0;
}

同样缝缝补补的稀碎代码。做法是创建一个新数组保存后k位,然后后移原本数组的前size-k位,再把后k位放前面就行。简单操作。

代码随想录的解析真的是强,比我的短多了:

#include<iostream>
#include<algorithm>
using namespace std;
int main() {
    int n;
    string s;
    cin >> n;
    cin >> s;
    int len = s.size(); //获取长度

    reverse(s.begin(), s.end()); // 整体反转
    reverse(s.begin(), s.begin() + n); // 先反转前一段,长度n
    reverse(s.begin() + n, s.end()); // 再反转后一段

    cout << s << endl;

} 

思路很清晰地解题,看了之后豁然开朗,这种方法我确实没想到,整体反转再分段反转,神了。

begin(),end()返回的是迭代器

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值