代码随想录个人笔记——字符串篇

发布时间 2023-09-07 21:10:54作者: DaxiaWan

344. 反转字符串

 题目链接

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

class Solution {
public:
    void reverseString(vector<char>& s) {
        int len = s.size();
        for(int i=0, j=len-1;i<j;i++,j--){
            //第一种
            // int temp = s[i];
            // s[i] = s[j];
            // s[j] = temp;
            //第二种
            // s[i] ^= s[j];
            // s[j] ^= s[i];
            // s[i] ^= s[j];
            swap(s[i],s[j]);
        }
        return ;
    }
};

 

 

541. 反转字符串II

题目链接

  • 注意for循环表达式设计,i += 2*k,每次移动2*k长度
class Solution {
public:
    void reverse(string &s, int i, int j){
        while(i<j){
            int temp = s[i];
            s[i] = s[j];
            s[j] = temp;
            i++;
            j--; 
        }
        return;
    }
    string reverseStr(string s, int k) {
        for(int i=0;i<s.size(); i += 2*k){
            if(i+k<=s.size()){
                reverse(s,i,i+k-1);
            }
            else{
                reverse(s,i,s.size()-1);
            }
        }
        return s;
    }
};

 

剑指offer 05. 替换空格

题目链接

  • 使用replace()函数
class Solution {
public:
    string replaceSpace(string s) {
        string c = "%20";
        for(int i=0;i<s.size();i++){
            if(s[i]==' '){
                s.replace(i,1,c);
            }
        }
        return s;
    }
};
  • 不用replace()函数,且原地替换
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. 翻转字符串里的单词

题目链接

  • 一般思路
class Solution {
public:
    string reverseWords(string s) {
        vector<string> a;
        string ans = "";
        for(int i=0;i<s.size();i++){
            if(s[i]!=' '){
                ans += s[i];
            }
            if(s[i] ==' '&&ans!=""){
                a.push_back(ans);
                ans = "";
            }
        }
        if(ans!=""){
            a.push_back(ans);
        }
        ans = "";
        for(int i=a.size()-1;i>=0;i--){
            if(i==0){
                ans += a[i];
            }
            else{
                ans += a[i] + ' ';
            }
        }
        return ans;
    }
};
  • 空间复杂度O(1)
    • 移除多余空格
    • 将整个字符串反转
    • 将每个单词反转
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;
    }
};

 

 

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

题目链接

  • 只能在原串操作
    • 局部反转+整体反转:假设串s = a + b;要得到 s = b + a,可以
      • 1.反转子串a
      • 2.反转子串b
      • 3.反转s
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;
    }
};

 

 

28. 实现strStr()

题目链接

  • 子串问题,如判断字符串A是否出现在字符串B中,并求出现次数。KMP求解
  • 关键点:构造前缀表(不减一版本,即最长相等前后缀)

C++ AC code:

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

class Solution {
public:
    //构造next数组(即最长相等前后缀)
    void getNext(int *next, string s){
        int j = 0;
        next[0] = 0;
        for(int i=1;i<s.size();i++){
            while(j>0&&s[i]!=s[j]){
                j = next[j-1];
            }
            if(s[i] == s[j]){
                j++;
            }
            next[i] = j;
        }
        return;
    }

    int strStr(string haystack, string needle) {
        int len = needle.size();
        int next[len];
        getNext(next,needle);
        int j = 0;
        for(int i=0;i<haystack.size();i++){
            while(j>0&&haystack[i]!=needle[j]){
                j = next[j-1];
            }
            if(haystack[i]==needle[j]){
                j++;
            }
            if(j==len){
                return i-len+1;
            }
        }
        return -1;
    }
};

 

459. 重复的子字符串

题目链接

  • 令s = ssss′,则有ss = s + s,掐头去尾后,如果能在ss中finds,则true,否则false,必要性证明略。
#include<bits/stdc++.h>
using namespace std;

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        string ss = s + s;
        ss.erase(ss.begin());//删头
        ss.erase(ss.end()-1);删尾
        if(ss.find(s) != string::npos){
            return true;
        }
        else{
            return false;
        }
    }
};

 

字符串总结

  • 对于C,字符串数组以'\0'结束符结尾,需遍历求长,即while(str[i]!='\0')
  • 对于C++,提供string类,有size接口,可直接str.size()求长
  • 一些技巧:原地操作、双指针、反转、KMP(重点理解next数组,最长相等前后缀)