代码随想录训练营第8天|LeetCode :344.反转字符串、 541. 反转字符串II、剑指Offer 05.替换空格、151.翻转字符串里的单词、剑指Offer58-II.左旋转字符串

参考

代码随想录
C/C++的字符串处理可以参考之前总结的两篇文章:C语言字符串的处理总结和C++字符串的处理总结

题目一:LeetCode 344.反转字符串

这个题是这几天来最简单的一个题了,没有难点,以中间为对称轴,两边交换即可。代码如下:

class Solution {
public:
    void reverseString(vector<char>& s) {
        int len = s.size();
        int mid = len / 2;
        for(int i=0;i<mid;i++)
        {
            char tmp = s[i];
            s[i] = s[len-i-1];
            s[len-i-1] = tmp;
        }
    }
};

这个题没必要使用C++里的reserve()函数,否则这个题就没有意义了。

题目二:LeetCode 541.反转字符串II

这个题在上一个题的基础上稍微增加了一些难度,但整体也不难。以2k个字符为一组,前k个反转,后k个保持原来的顺序,以这样的方式进行循环,代码实现如下:

class Solution {
public:
    string reverseStr(string s, int k) {
        string res,sub;
        int size = s.size();
        int index = 0;
        while(index < size)
        {
            sub = s.substr(index,k);
            reverse(sub.begin(),sub.end());
            res += sub;
            index += k;
            if(index < size) // 判断是否还有字符
            {
                sub = s.substr(index,k);
                res += sub;  //保持原来的顺序
                index += k;
            }
        }
        return res;
    }
};

上一个题已经会怎么反转字符串了,所以这个题可以直接调用reserve()函数,另外还用了substr()函数,第一个参数是起始位置,第二个参数是长度,如果长度超过字符串的长度就忽略超出的部分,所以不需要担心越界。
如果不是用额外的空间,直接在原来的字符串上进行反转,代码如下:

class Solution {
public:
    string reverseStr(string s, int k) {
        for(int i=0;i<s.size();i += 2*k)
            if(i + k < s.size()) //足够k个字符
                reverse(s.begin()+i,s.begin()+i+k);
            else  //不足k个字符
                reverse(s.begin()+i,s.end());
        return s;
    }
};

题目三:剑指Offer 05.替换空格

定义一个新的string变量来保存结果res,遍历字符串,如果是空格,则res += “%20”,否则将这个字符添加到res中,非常的简单。

class Solution {
public:
    string replaceSpace(string s) {
        string res;
        for(int i=0;i<s.size();i++)
        {
            if(s[i] != ' ') res += s[i];
            else    res += "%20";
        } 
        return res;
    }
};

代码随想录中给出了不用额外申请空间(对原来的字符串进行扩容)的方法,但必须先遍历一遍数组,得到空格的出现的次数,然后再在原来空间的基础之上进行扩充,这样做的好处是节省空间,缺点是相对要多消耗一些时间,代码如下:

class Solution {
public:
    string replaceSpace(string s) {
        int count = 0; // 统计空格的个数
        int sOldSize = s.size();
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == ' ') {
                count++;
            }
        }
        // 扩充字符串s的大小,也就是每个空格替换成"%20"之后的大小
        s.resize(s.size() + count * 2);
        int sNewSize = s.size();
        // 从后先前将空格替换为"%20"
        for (int i = sNewSize - 1, j = sOldSize - 1; j < i; i--, j--) {
            if (s[j] != ' ') {
                s[i] = s[j];
            } else {
                s[i] = '0';
                s[i - 1] = '2';
                s[i - 2] = '%';
                i -= 2;
            }
        }
        return s;
    }
};

题目四:151.翻转字符串里的单词

先将字符串以空格进行分割,放入到vector中,然后从后往前重构字符串,每个子串后面要添加一个空格(最后一个子串除外),字符串的分割可参考C++字符串的处理总结中的字符分割。

class Solution {
public:
    string reverseWords(string s) {
        stringstream ss(s);
        string str;
        vector<string> vec;
        //分割字符串
        while(ss >> str)    vec.push_back(str);
        str = "";
        //从后往前添加
        for(int i=vec.size()-1;i>=0;i--)
        {
            str += vec[i];
            str += " ";
        }
        str.erase(str.end()-1);
        return str;
    }
};

代码随想录里提供了另一解题思路,不使用额外的辅助空间,解题步骤如下:

  • 移除多余空格
  • 将整个字符串反转
  • 将每个单词反转
    按照上述解题步骤的代码实现如下:
class Solution {
public:
    string reverseWords(string s) {
        int i = 0, j = 0;
        //去除开头的空格
        while(i < s.size() && s[i] == ' ')  i++;
        //去除中间和末尾的字符
        while(i < s.size())
        {
            if(s[i] != ' ') s[j++] = s[i++];
            else
            {
                //去除空格
                while(i < s.size() && s[i] == ' ')  i++;
                if(i < s.size())    s[j++] = ' '; //添加单词间的空格
            }
        }
        s.resize(j);  //重新指定大小
        //反转这个字符串
        reverse(s.begin(),s.end());
        //反转每个单词
        i = 0,j = 0;
        while(i < s.size())
        {
            while(i < s.size() && s[i] != ' ') i++;
            reverse(s.begin()+j,s.begin()+i);
            j = ++i;
        }
        return s;
    }
};

题目五:剑指Offer58-II.左旋转字符串

简单粗暴的调用函数:

class Solution {
public:
    string reverseLeftWords(string s, int n) {
        string str1 = s.substr(0,n);
        string str2 = s.substr(n);
        return str2+str1;
    }
};

注意返回时是str2+str1,和str1+str2不一样!!!
代码随想录提供了另一种思路,同样不需要额外的辅助空间,思路如下:

  • 反转区间为前n的子串
  • 反转区间为n到末尾的子串
  • 反转整个字符串
    代码实现如下:
class Solution {
public:
    string reverseLeftWords(string s, int n) {
        reverse(s.begin(), s.begin() + n);
        reverse(s.begin() + n, s.end());
        reverse(s.begin(), s.end());
        return s;
    }
};

今日小结

今天的题可以难也可以简单,如果都通过调函数来实现就很简单,如果要求空间复杂度为O(1),只能在原来的字符串上进行变换则就有一定的难度了。平时练习的时候注意多种方法的实现,特别是不使用额外的辅助空间,一方面能帮助真正掌握字符串的处理,另一方面也能够锻炼编程能力。

你可能感兴趣的:(代码随想录训练营,leetcode,算法,职场和发展,c++)