第四章 字符串

文章介绍了多个关于字符串处理的算法问题,包括LeetCode上的题目,如反转字符串、替换空格、反转单词、左旋转字符串,以及使用KMP算法实现的字符串匹配,并探讨了如何找到重复的子字符串。解决方案涉及到了双指针、字符串翻转和前缀数组等概念。
摘要由CSDN通过智能技术生成

一、反转字符串

Leetcode 344

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

二、反转字符串 II

Leetcode 541

使用库函数 reverse()

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

三、替换空格

剑指 Offer 05

为了将时间复杂度做到 O ( n ) O(n) O(n),空间复杂度做到 O ( 1 ) O(1) O(1),可以先统计字符串中空格的个数,然后将字符串长度扩充到替换后的字符串的长度。接下来,采用双指针从后往前遍历, i i i 指向新长度的末尾, j j j 指向旧长度的末尾,遇到空格就替换掉。

class Solution {
public:
    string replaceSpace(string s) {
        int cnt = 0, len_old = s.size();
        for (char c: s) // 统计空格个数
            if (c == ' ') cnt ++ ;
        s.resize(len_old + cnt * 2);
        int len_new = s.size();
        for (int i = len_new - 1, j = len_old - 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;
    }
};

四、反转字符串中的单词

Leetcode 151

  • 先去掉多余空格(快慢指针)
  • 翻转整个字符串
  • 翻转每个单词
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 removeExtraSpace(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) {
        removeExtraSpace(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;
    }
};

五、左旋转字符串

剑指 Offer 58 -Ⅱ

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

六、找出字符串中第一个匹配项的下标(KMP算法实现)

Leetcode 28

详细 KMP 算法解释见参考文章

看文章时应该注意几点:

  • 前后缀数组的含义,注意理解图中这句话在这里插入图片描述
  • next 数组与前后缀数组的联系
class Solution {
public:
    void getNext(int *next, const string& s) {
        next[0] = 0;
        for (int i = 1, j = 0; i < s.size(); i ++ ) {
            while (j && s[i] != s[j]) j = next[j - 1];
            if (s[i] == s[j]) j ++ ;
            next[i] = j;
        }
    }

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

七、重复的子字符串

Leetcode 459

解题关键:在由重复子串组成的字符串中,最长相等前后缀不包含的子串就是最小重复子串

参考题解

class Solution {
public:
    void getNext(int* next, const string& s) {
        next[0] = 0;
        for (int i = 1, j = 0; i < s.size(); i ++ ) {
            while (j && s[i] != s[j]) j = next[j - 1];
            if (s[i] == s[j]) j ++ ;
            next[i] = j;
        }
    }

    bool repeatedSubstringPattern(string s) {
        int next[s.size()];
        getNext(next, s);
        int len = s.size();
        if (next[len - 1] != 0 && len % (len - next[len - 1]) == 0) 
            return true;
        return false;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值