Bootstrap

Studying-代码随想录训练营day8| 344.反转字符串、541.反转字符串II、卡码网:54.替换数字

第八天,✊o(* ̄▽ ̄*)ブ✊,编程语言:C++;

目录

344.反转字符串

541.反转字符串II

卡码网54.替换数字

总结 


344.反转字符串

文档讲解:代码随想录反转字符串

视频讲解:手撕反转字符串

题目:

初看:第一想法是采用一对左右指针,分别指向字符串初始位置和终点位置,之后两两进行交换。再不断往内缩进,循环判断left < right。

注意:本题直接采用库函数reverse( )同样可以实现字符串反转,但本题不适合直接使用库函数,一般来说,如果题目关键的部分直接用库函数就可以解决,建议不使用库函数。而如果库函数仅仅是解题过程中的一小部分,可以考虑使用库函数。

本题使用双指针法,和数组中的双指针法基本一样,因为字符串也是一种数组,元素再内存中是连续分布的。

代码:

//时间复杂度O(n)
//空间复杂度O(1)
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

文档讲解:代码随想录反转字符串II

视频讲解:手撕反转字符串II

题目:

初看: 第一想法是首先构造一个交换函数,交换k个字符。其次通过一个循环,每次取出2k个字符的前k个字符。最后单独处理不足2k个字符的情况,如果剩下的超过k个字符,就取出k个字符,不超过k个字符,则取出到end()的字符。

//时间复杂度O(n)
//空间复杂度O(n)
class Solution {
public:
    void swapstring(string &s, int left, int right) {
        while (left < right) {
            swap(s[left], s[right]);
            left++;
            right--;
        }
    }

    string reverseStr(string s, int k) {
        int n = s.size();
        int loop = n / (2*k);
        int left= 0;
        int right = k - 1;
        while(loop--) {
            swapstring(s, left, right);
            left += 2*k;
            right += 2*k;
        }
        right = min(right, n - 1);
        swapstring(s, left, right);
        return s;
    }
};

学习:本题不同于上一题,关键部分在于如何取出前k个字符,因此可以直接采取库函数reverse()反转k个字符。

代码:

//时间复杂度O(n)
//空间复杂度O(1)
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;
    }
};

收获:

  1.  此处循环要注意i的变化,不能简单的写为i++,这样的话,还需要设置一个count值来计数2k个。for循环每个部分的含义要搞清楚,当需要固定规律一段一段去处理字符串说的时候,要想想在for循环的表达式上做文章。

卡码网54.替换数字

文档讲解:代码随想录替换数字

题目:

初看:第一想法是,首先创建一个新的字符串ans,再设置两个指针分别指向给定的字符串s和新字符串ans的初始位置。之后遍历字符串s,当遇到数字时,字符串ans+=“number”,当不是数字时,ans+=s[i]。

代码:

//时间复杂度O(n)
//空间复杂度O(n)
#include <iostream>
using namespace std;
 
int main() {
    string s;
    cin >> s;
    string ans;
    int i = 0;
    int j = 0;
    for ( ; i < s.size(); i++) {
        if(s[i] >= '0' && s[i] <= '9') {
            ans += "number";
        }
        else {
            ans += s[i];
        }
    }
    cout << ans << endl;
     
    system("pause");
    return 0;
}

学习: 本题也可以不创建一个新的字符串,而是先通过扩展字符串长度到指定长度。之后设置两个新老指针,通过双指针的方式,插入字符,达到效果。

//时间复杂度O(n)
//空间复杂度O(1)
#include <iostream>
using namespace std;
int main() {
    string s;
    while (cin >> s) {
        int sOldIndex = s.size() - 1;
        int count = 0; // 统计数字的个数
        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 sNewIndex = s.size() - 1;
        // 从后往前将数字替换为"number"
        while (sOldIndex >= 0) {
            if (s[sOldIndex] >= '0' && s[sOldIndex] <= '9') {
                s[sNewIndex--] = 'r';
                s[sNewIndex--] = 'e';
                s[sNewIndex--] = 'b';
                s[sNewIndex--] = 'm';
                s[sNewIndex--] = 'u';
                s[sNewIndex--] = 'n';
            } else {
                s[sNewIndex--] = s[sOldIndex];
            }
            sOldIndex--;
        }
        cout << s << endl;       
    }
    system("pause");
    return 0;
}

收获:

  1. 数组填充类的问题,其做法都是先预先给数组扩容待填充后的大小,然后再从后向前进行操作。这么做有两个好处:①不用申请新数组;②从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要讲添加元素之后的所有元素向后移动的问题。
  2. 字符串和数组的区别,字符串是若干字符组成的有限序列,也可以理解为是一个字符数组,但是很多语言对字符串做了特殊的规定。其中c语言,把一个字符串存入一个数组时,也把结束符 '\0'存入数组,并以此作为该字符串是否结束的标志。
char a[5] = "asd";
for (int i = 0; a[i] != '\0'; i++) {
}

在C++中,提供一个string类,string类会提供 size接口,可以用来判断string类字符串是否结束,就不用'\0'来判断是否结束。

string a = "asd";
for (int i = 0; i < a.size(); i++) {
}

vector<char> 和string之间,在基本操作上没有区别,但是string提供更多的字符串处理的相关接口,例如string 重载了+,而vector却没有。所以想处理字符串,最后还是定义一个string类型。


总结 

要注意for循环的特殊使用,包括还有for(auto a : c)的模式,以及字符串和数组的区别。至今为止,目前解决的双指针题目有:27.移除元素、15.三数之和、18.四数之和、206.反转链表、142.环形链表II、344.反转字符串。

;