day9打卡 字符串 【KMP算法】

我忘记C++对string操作的接口函数了
例如string如何填充字符。C++ string可以使用下标操作

541 反转字符串 【双指针】

leetcode 541
在这里插入图片描述

class Solution {
public:
    void reverStr(string& s, int start, int end) {
        char tmp;
        while(start < end) {
            tmp = s[end];
            s[end] = s[start];
            s[start] = tmp;
            start++;
            end--;
        }
    }

    string reverseStr(string s, int k) {
        int l = 0;
        int m = k - 1;
        int r = 2 * k - 1;
        while(r < s.size()) {
            reverStr(s, l, m);
            l = r + 1;
            m = l + k - 1;
            r += 2 * k;
        }

        if(s.size() - l < k) {
            reverStr(s, l, s.size() - 1);
        } else {
            reverStr(s, l, l + k - 1);
        }
        return s;
    }
};

卡码网 替换字符串中的数字

卡码网54 替换数字
在这里插入图片描述
思路:使用双指针替换,注意对C++ String进行resize

#include <iostream>
using namespace std;
 
int main() {
    string input;
    cin >> input;
     
    // 怎么判断char是字母还是数字啊
    int cnt = 0;
     
    for(int i = 0; i < input.size(); i++) {
        if(input[i] <= '9' && input[i] >= '0') {
            cnt++;
        }
    }
     
    int old = input.size() - 1;
    input.resize(input.size() + cnt *5);
    int end = input.size() - 1;
     
    while(old > -1) {
        if(input[old] <= '9' && input[old] >= '0') {
            input[end--] = 'r';
            input[end--] = 'e';
            input[end--] = 'b';
            input[end--] = 'm';
            input[end--] = 'u';
            input[end--] = 'n';
            old--;
        } else {
            input[end--] = input[old--];
        }
         
    }
     
    cout << input << endl;
     
     
}

151 反转字符串中的单词【双指针】

leetcode 151
在这里插入图片描述
思路: 可以使用先把整个字符串删除空格,再把整个字符串反转,再挨个反转单词的方式。也可以直接采用双指针的方式反转字符串。

//解法1
class Solution {
public:
    string reverseWords(string s) {
        // 1 先删除所有空格
        // 2 把整个字符串反转
        // 3 反转每个单词
        
        // 1 删除所有空格用快慢指针
        int slow = 0;

        for(int fast = 0; fast < s.size(); fast++) {
            if (fast == 0 && s[fast] == ' ') {
                continue;
            } else if (s[fast] != ' ') {
                s[slow++] = s[fast];
            } else if (s[fast] == ' ' && s[fast - 1] != ' ') {
                s[slow++] = ' ';
            } else {
                continue;
            }
        } 

        if(s[slow - 1] == ' ') slow--;

        s.resize(slow);
        cout << s << endl;

        int start = 0;
        int end = s.size() - 1;
        while(start < end) {
            swap(s[start], s[end]);
            start++;
            end--;
        }

        cout << s;


        int s1 = 0;
        int e = 0;

        while(e < s.size()) {
            if(s[e] != ' ' && e != (s.size() - 1)) {
                e++;
                continue;
            } else if(s[e] == ' ' || e == (s.size() - 1)){
                start = s1;

                if(s[e] == ' ') {
                    end = e-1; 
                } else {
                    end = e;
                }
               
                while(start < end) {
                    swap(s[start], s[end]);
                    start++;
                    end--;
                }
                e++;
                s1 = e;
            }
        }

        return s;





        return s;


    }
};

解法2:直接使用双指针

class Solution {
public:
    string reverseWords(string s) {
        string result;
        int start = 0;
        int wordEnd = s.size() - 1;
        int wordLen = 0;
        int i;
        // 从后向前扫描string s中的char
        while(wordEnd > -1) {
            if(s[wordEnd] == ' ' && wordLen != 0) {
                // 遇到空格,且当前扫描到的word不为空
                i = 1;
                //cout << "word len is" <<  wordLen << endl;
                while(i <= wordLen) {
                    result.push_back(s[wordEnd + i]); 
                    i++;
                }
                wordEnd--;
                wordLen = 0;
                result.push_back(' '); 
            } else if(s[wordEnd] == ' ' && wordLen == 0) {
                wordEnd--;
                continue;
            } else {
                wordEnd--;
                wordLen++;
            }
        }

        if(wordLen != 0) {
             //cout << "word len is" <<  wordLen << endl;
            i = 1;
            while(i <= wordLen) {
                result.push_back(s[wordEnd + i]); 
                i++;
            }
            result.push_back(' ');
        }

        result.pop_back();
        return result;
    }
};

Kama 55 右旋字符串

kama 55 右旋字符串
在这里插入图片描述

#include<iostream>
using namespace std;
 
 
int main() {
    int n;
    string s;
     
    cin >> n;
    cin >> s;
 
    if ( n > s.size() ) {
        return 0;
    }
 
    int begin = 0;
    int end = s.size()-1;
     
    while( begin < end ) {
        swap(s[begin++], s[end--]);
    }
     
    begin = 0;
    end = n - 1;
    while( begin < end ) {
        swap(s[begin++], s[end--]);
    }
     
    begin = n;
    end = s.size() - 1;
    while( begin < end ) {
        swap(s[begin++], s[end--]);
    }
     
    cout << s;
     
     
}

leet 28 找出字符串中第一个匹配的下标 【KMP算法】

leet 28 找出字符串中第一个匹配的下标
在这里插入图片描述

思路

KMP解法:通过已经掌握的信息去规避重复的字符串匹配操作

视频讲解

理解KMP前缀表的含义很重要
KMP前缀表:记录需匹配字符串needle中每个位置存在的最大相同前后缀的长度。

有了需匹配字符串needle的最大前后缀的信息,在haystack中匹配的时候,若haystack中出现匹配错误时,
就可直接跳过匹配错误部分的后缀字符串 与 前缀字符串 相同的部分。而这个跳过的字符串的长度是多少,就是由KMP数组记录的。

求KMP算法的前缀表的方法:

class Solution {
public:
    int strStr(string haystack, string needle) {
        if (needle.size() > haystack.size()) return -1;
        if (needle.size() == 0) return 0;

        int result = -1;
        //使用kmp算法, 时间复杂度还是O(n * m)
        // 第一步,先求出前缀表
        // 使用双指针法构建 needle 的前缀数组 kmp[]
        int preFixLen= 0; // preFixLen:当前共同前后缀的长度
        int i = preFixLen + 1;
        int kmp[needle.size()];


        kmp[0] = 0;
        while(i < needle.size()) {
            if (needle[i] == needle[preFixLen]) {
                // 当前char相同,则 共同前后缀长度++
                kmp[i] = preFixLen + 1;
                preFixLen++;
                i++;
            } else {
                while(needle[preFixLen] != needle[i] && preFixLen > 0) {
                     // 如果当前char不相同,则通过回退前缀数组kmp[]
                     // 利用前缀数组中的已知信息,找到新的前后缀数组
                     preFixLen = kmp[--preFixLen];
                }

                if(needle[i] == needle[preFixLen]) {
                    // 若找到了共同前缀,则从该preFixLen继续计算kmp数组
                    kmp[i] = preFixLen + 1;
                    i++;
                    preFixLen++;
                } else {
                    // 未匹配,则从0开始,重新计算前缀
                    kmp[i] = 0;
                    i++;
                }
            }
        }



        // 利用前缀数组进行匹配
        int p1 = 0, p2 = 0;
        while( p1 < haystack.size() ) {

            if( haystack[p1] == needle[p2] ) {
                if(p2 == needle.size() - 1) {
                    return p1 - (needle.size() - 1);
                } else {
                    p1++;
                    p2++;
                }
            } else {
                while( p2 > 0 && haystack[p1] != needle[p2] ) {
                    p2 = kmp[p2 - 1];
                }

                if( haystack[p1] == needle[p2]) {
                    p1++;
                    p2++;
                } else {
                    p1++;
                }
                
            }
        }




        return result;
    }
};

459 重复的子字符串

leet 459
在这里插入图片描述

思路

这题也用到了KMP算法的KMP数组,只不过判断是否是由重复字符串组成时,首先要判断KMP数组最后一位不为0,即字符串存在最大相同前后缀。 其次该字符串的 子字符串的长度,应该为 s.size() - kmp[s.size() -1], 子字符串的长度要能被整个字符串长度整除才行。

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        // 该字符串的KMP数组,应该满足KMP数组的最后一个数不为0,且KMP数组的长度应该是 值为0的字符串前缀的整数倍
        if(s.size() == 1) return false;

        int kmp[s.size()];

        int preFixLen = 0;
        int subStrLen = 0;
        kmp[preFixLen] = 0;

        for(int i = preFixLen + 1; i < s.size(); i++) {
            if(s[i] == s[preFixLen]) {
                kmp[i] = ++preFixLen;
            } else {
                while(preFixLen > 0 && s[i] != s[preFixLen]) {
                    preFixLen = kmp[--preFixLen];
                }

                if(s[i] == s[preFixLen]) {
                    kmp[i] = ++preFixLen;
                } else {
                    kmp[i] = 0;
                }
            }
        }

        if(kmp[s.size() - 1] == 0) return false;
        subStrLen = s.size() - kmp[s.size() - 1];

        if((s.size() % subStrLen == 0)) {
            return true;
        } else {
            return false;
        }
    }
};
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值