代码随想录算法训练营第八天 | LeetCode 344. 反转字符串 541. 反转字符串 II 151. 反转字符串中的单词 剑指Offer58-II.左旋转字符串

344. 反转字符串

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

题目很简单,直接放上代码,其中交换的部分可以使用swap函数替代

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

541. 反转字符串 II

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

我自己的解法思路是创建一个string对象,保留每次操作完剩余的字符串,然后用substr方法获取需要的字串存入result中,这样的做法在代码层面比较复杂,不便于编写

class Solution {
public:
    string reverseStr(string s, int k) {
        for (int i = 0; i < s.size(); i += (2 * k)) {
            // 1. 每隔 2k 个字符的前 k 个字符进行反转
            // 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
            if (i + k <= s.size()) {
                reverse(s.begin() + i, s.begin() + i + k );
            } else {
                // 3. 剩余字符少于 k 个,则将剩余字符全部反转。
                reverse(s.begin() + i, s.end());
            }
        }
        return s;
    }
};

卡哥的解法中,for循环每次的执行命令i +=2*k我认为是比较关键的,这样的处理方式使得每次反转的起始位置发生变化,相当于移除了已经操作完毕的字符串,并且没有占用额外的内存空间,值得我学习

151. 反转字符串中的单词(难)

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

题目比较难,思路正确但是有些东西难以用代码实现,导致无法独立完成,比如说去除了字符串的多余空格后怎么把字符串的位置进行调整保证索引完整

对我来说这题的主要难点在于怎么在把字符串整体反转后去除单词之间的多余空格,去除首尾的空格可以想到办法解决。答案是去除字符串的所有空格后再给单词之间添加额外的空格,着重关注removeExtraSpaces的写法,它实际上是对字符串后续所有内容向前移动并且在两个单词之间加上空格的一个过程,类似于27题中移除元素的双指针法的应用,但是这道题目增加了一个添加空格的逻辑,更加复杂

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;
    }
};

剑指Offer 05.替换空格

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

本题非常简单,而简单的原因就在于.和一个空格所占的空间大小是一样的,因此直接替换就可以

而对于下面这个题就会复杂很多:

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

示例 1: 输入:s = "We are happy."
输出:"We%20are%20happy."

对于空间不一样的题目,我们需要先遍历字符串,找出需要扩充的空间大小,然后再从后向前进行填充,避免所有的字符都要向后移动

对于线性数据结构,填充或者删除,后序处理会高效的多

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;
    }
};

剑指Offer58-II.左旋转字符串 (难)

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

如果可以申请额外的内存空间,题目还是比较简单的

class Solution {
public:
    string dynamicPassword(string password, int target) {
        string substr = "";
        int i = 0;
        while(i < target)
        {
            substr += password[i];
            i++;
        }
        for(int j = 0;i < password.size();i++,j++)
        {
            password[j] = password[i];
        }
        password.resize(password.size() - target);
        password += substr;
        return password;
    }
};

接下来提升题目的难度,即在原串中进行操作

通过局部反转+整体反转 达到左旋转的目的:

  1. 反转区间为前n的子串
  2. 反转区间为n到末尾的子串
  3. 反转整个字符串

也就是各自反转后整体反转等于切割后两部分按原顺序拼在一起了

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;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值