训练营 day08 | 344.反转字符串 541. 反转字符串II 卡码网:54.替换数字 151.翻转字符串里的单词 卡码网:55.右旋字符串

344.反转字符串

题目链接:反转字符串

视频讲解:字符串基本操作

        用双指针法对reverse函数进行重写。

// 时间复杂度: O(n)
// 空间复杂度: O(1)
class Solution {
public:
    void reverseString(vector& s) {
        for (int i = 0, j = s.size() - 1; i < s.size()/2; i++, j--) {
            swap(s[i],s[j]);
        }
    }
};

541. 反转字符串II

题目链接:反转字符串II

视频讲解:字符串进阶操作

        主要理清反转规则,代码就不会写的那么冗长。在遍历字符串时,让i每次移动2 * k步,对移动的区间进行翻转就可以了。

// 时间复杂度: O(n)
// 空间复杂度: O(1)
class Solution {
public:
    string reverseStr(string s, int k) {
        for (int i =0; i < s.length(); i += 2 * k)
        {
            if (i + k <= s.length())  //2k个字符的qia前k个字符进行反转
            {
                reverse(s.begin() + i, s.begin() + i + k);
            }
            else // 不足k个字符,剩余的全部反转
            {
                reverse(s.begin() + i, s.end());
            }
        }
        return s;
    }
};

卡码网:54.替换数字

题目链接:替换数字

        此题依然用双指针的方法。首先是要把字符串扩容到数字换成number后的大小,用双指针时应该从后向前替换数字字符。填充number也要从后向前开始,若是从前向后每次添加元素都要把添加元素之后的元素向后移,增加了时间复杂度。

很多数组填充类的问题,其做法都是先预先给数组扩容,然后再从后向前进行操作。这样就不用申请新的数组,同时避免了从前向后添加元素时,还要将填充后的元素向后移动。

// 时间复杂度:O(n)
// 空间复杂度:O(1)
#include 
#include 
using namespace std;

int main()
{
    string s;
    while (cin >> s)
    {
        int count = 0; // 统计字符串中数字的个数,方便扩容
        int len = s.size();
        for (int i = 0; i < len; i++)
        {
            if (s[i] >= '0' && s[i] <= '9')
            {
                count++;
            }
        }
    // 将字符串扩容
    s.resize(s.size() + 5 * count);
    for (int i = s.size() -1 , j = len - 1; j < i; j--, i--)
    {
        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;
    }
}

151.翻转字符串里的单词

题目链接:翻转字符串里的单词

视频讲解:字符串复杂操作拿捏了!

        要先考虑好怎么去翻转字符串里的单词,思考一下,我们可以先将整个字符串反转,此时单词是个反的,然后再逐个反转单词。

方法

1、移除多余的空格;

2、反转整个字符串;

3、逐个反转单词;

移除多余的空格也有很多细节需要考虑,我们可以多创建一个字符串,将原字符串里需要的元素放入新字符串,但这样空间复杂度就增加了。也可以在保持空间复杂度为O(1)同时,删去多余的空格,这就要用到双指针法了,与删除数组中的元素类似。

我们可以先删除字符串中的所有空格,然后再在相邻单词之间加一个空格,这样就不需要判断原字符串中哪些空格需要删,哪些不需要。

学习总结:

1、重温了反转字符串;

2、移除元素,双指针很好用;

3、本题移除元素后要更新字符串的大小;

// 时间复杂度: O(n)
// 空间复杂度: O(1) 或 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 reverseExtraSpaces(string& s) // 去除所有空格,并在相邻单词之间添加空格
    {
        int slow = 0; // 慢指针
        for (int i = 0; i < s.size(); ++i) // 快指针遍历
        {
            if (s[i] != ' ') // 去除空格
            {
                if (slow != 0) s[slow++] = ' '; // 在单词后面添加空格,第一个单词前不加
                while(i < s.size() && s[i] != ' ') // 获取单词,遇到空格表示一个单词结束,出循环后先删空格再添加一个空格
                {
                    s[slow++] = s[i++];
                }
            }
        }
        s.resize(slow); // 更新字符串的大小
    }

    string reverseWords(string s) {
        reverseExtraSpaces(s); // 去除多余的空格
        reverse(s, 0, s.size() - 1); // 反转整个字符串
        int start = 0;
        for (int i = 0; i <= s.size(); ++i) // 把每个单词反转回来
        {
            if (i == s.size() || s[i] == ' ') // 到达串尾或空格,表示一个单词结束,反转该单词
            {
                reverse(s, start, i - 1); // 左闭右闭反转
                start = i + 1; // 更新遍历起始点
            }
        }
        return s;
    }
};

卡码网:55.右旋字符串

题目链接:右旋字符串

        此题需要在不增加空间复杂度的基础上完成,即不申请额外的空间,只能在本串上操作

做了上一题,我么可以从中受到启发,怎么反转子串。我们先可以把整个字符串全部反转,反转后字母顺序也反转了。这时就可以把字符串分为两部分,前一部分是需要右旋的位数,这几位数本来在后面,整个字符串反转后到了前面但是顺序变了,同理后一部分字符的顺序也变了。我们分别再反转这两部分就可以得到右旋字符串了。

训练营 day08 | 344.反转字符串 541. 反转字符串II 卡码网:54.替换数字 151.翻转字符串里的单词 卡码网:55.右旋字符串_第1张图片

整体反转后

训练营 day08 | 344.反转字符串 541. 反转字符串II 卡码网:54.替换数字 151.翻转字符串里的单词 卡码网:55.右旋字符串_第2张图片

子串反转

训练营 day08 | 344.反转字符串 541. 反转字符串II 卡码网:54.替换数字 151.翻转字符串里的单词 卡码网:55.右旋字符串_第3张图片


#include 
#include 
#include 
using namespace std;

int main()
{
    int k;
    string s;
    cin >> k;
    cin >> s;
    
    reverse(s.begin(), s.end());
    reverse(s.begin(), s.begin() + k);
    reverse(s.begin() + k, s.end());
    
    cout << s << endl;
}

你可能感兴趣的:(算法)