Day11 LeetCode151.反转字符串中的单词 剑指 Offer 58 - II. 左旋转字符串 28. 找出字符串中第一个匹配项的下标 459. 重复的子字符串

LeetCode151.反转字符串中的单词

题目:151. 反转字符串中的单词 - 力扣(LeetCode)

思路:

        1.先把字符串中多余的空格去除

        2.反转整个字符串

        3.再单独反转字符串中的每个单词

代码:

class Solution {
public:
      void removeExtraSpaces(string& s){
        int slow = 0;
        for(int fast = 0; fast < s.size(); fast++){
            if(s[fast] != ' '){
                if(slow != 0) s[slow++] = ' ';
                while(fast < s.size() && s[fast] != ' '){
                    s[slow++] = s[fast++];
                }
            }
        }
        s.resize(slow);
    }
    void reverse(string& s, int start, int end){
        for(int i = start, j = end; i < j; i++, j--){
            swap(s[i], s[j]);
        }
    }
    string reverseWords(string s) {
        removeExtraSpaces(s);
        reverse(s, 0, s.size() - 1);
        int start = 0;
        for(int i = 0; i <= s.size(); i++){
            if(s[i] == ' ' || i == s.size()){//当到达空格或者字符串尾,说明一个单词遍历结束或者整个字符串遍历结束
                reverse(s, start, i-1);//翻转[start,i-1],即翻转一个单词
                start = i + 1;/*更新start,此时i指向空格,让start指向空格的下一个位置即
            i+1*/
            }
            
        }
        return s;
    }
};

剑指 Offer 58 - II. 左旋转字符串  

题目:剑指 Offer 58 - II. 左旋转字符串 - 力扣(LeetCode) 

 思路:

        1.先反转前n个字符

        2.再反转n到字符串末尾个字符

        3.最后反转整个字符串

代码:

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]);
        }
    }
    string reverseLeftWords(string s, int n) {
        reverse(s, 0, n - 1);
        reverse(s, n, s.size() - 1);
        reverse(s, 0, s.size() - 1);
        return s;
    }
};

LeetCode28. 找出字符串中第一个匹配项的下标

题目:28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)

 思路:这是一道典型的KMP算法,模式串和文本串的快速匹配,核心在于匹配过程中如何利用其已经匹配相同的部分,就是当匹配不成功时,模式串不用在从头开始匹配,而是j跳到其最大公共前缀的后一个位置,此时文本串中i指向其最大公共后缀的后一个位置,因为文本串和模式串相同部分的最大公共前缀和后缀肯定也相同。这儿涉及到一个next[]数组,模式串中j的回跳就是根据next[]数组实现,j是根据其前一个元素j-1在next数组中的值来往回跳,即j = next[j - 1]。

具体分析见:代码随想录 (programmercarl.com)

代码:

class Solution {
public:
    void getnext(int* next, const string& s){
        //j指向前缀末尾的位置,i指向后缀末尾的位置
        int j = 0;
        next[0] = 0;
        for(int i = 1; i < s.size(); i++){//i从下标1的位置开始
            while(j > 0 && s[j] != s[i]){//如果前后缀末尾不相同的情况,就要向前回退,j回退到前一个元素再next数组中的值
                j = next[j - 1];//j
            }
            if(s[j] == s[i]){//如果 s[i] 与 s[j] 相同,那么就同时向后移动i 和j 说明找到了相同的前后缀,同时还要将j(前缀的长度)赋给next[i], 因为next[i]要记录相同前后缀的长度。
                j++;
            }
            next[i] = j;
        }
    }
    int strStr(string haystack, string needle) {
        int next[needle.size()];
        getnext(next, needle);
        int j = 0;
        for(int i = 0; i < haystack.size(); i++){
            while(j > 0 && needle[j] != haystack[i]){
                j = next[j - 1];
            }
            if(needle[j] == haystack[i]){
                j++;
            }
            if(j == needle.size()){
                return(i - needle.size() + 1);
            }
        }
        return -1;
    }
};

 LeetCode459. 重复的子字符串 

题目:459. 重复的子字符串 - 力扣(LeetCode)​​​​​​

思路:还是用KMP算法,在由重复子串组成的字符串中,最长相等前后缀不包含的子串就是最小重复子串,其中next数组记录的就是最长相等前后缀,len是字符串的长度,如果len % (len - (next[len - 1] + 1)) == 0 ,则说明数组的长度正好可以被 (数组长度-最长相等前后缀的长度) 整除 ,说明该字符串有重复的子字符串。

具体分析见:代码随想录 (programmercarl.com)

代码:

class Solution {
public:
    void getnext(int* next, const string& s){
        int j = 0;
        next[j] = 0;
        for(int i = 1; i < s.size(); i++){
            while(j > 0 && s[j] != s[i]){
                j = next[j - 1];
            }
            if(s[j] == s[i]){
                j++;
            }
            next[i] = j;
        }
    }
    bool repeatedSubstringPattern(string s) {
        int next[s.size()];
        getnext(next, s);
        int j = 0;
        int len = s.size();
        if(next[len - 1] != 0 && len % (len - next[len - 1]) == 0){
            return true;
        }
        return false;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值