【代码随想录|151.反转字符串中的单词、55.右旋字符、28.找出字符串找那个第一个匹配的下标、459.重复的子串】

字符串算法题解析:反转、匹配与重复子串

151.反转字符串中的单词

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

class Solution {
public:
void removeExtraSpaces(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() - 1 && s[i] != ' '){
                s[slow++] = s[i++];
            }
        }
    }
   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(i == s.size() || s[i] == ' ') {
                reverse(s,start, i - 1);
                start = i+1;
            }
        }
        return s;
    }
};

55.右旋字符

55. 右旋字符串(第八期模拟笔试)

using namespace std;
#include<iostream>
#include<algorithm>
int main() {
	int n;
	string s;
	cin >> n;
	cin >> s;
	reverse(s.begin(), s.end());
	reverse(s.begin(), s.begin() + n);
	reverse(s.begin() + n, s.end());
	cout << s << endl;
	return 0;
}

28.找出字符串找那个第一个匹配的下标

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

class Solution {
public:
    void getNext(vector<int>& next, string& s) {
        int j = 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;
        }
    }
    int strStr(string haystack, string needle) {
        vector<int> next(needle.size());
        next[0] = 0;
        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 == needle.size()) {
                return i - needle.size() + 1;
            }
        }
        return -1;
    }
};

这里的顺序得是

  1. 先处理不匹配的情况(回退 j),避免无效匹配。

  2. 再处理匹配的情况j++),推进匹配进度。

  3. 最后记录 next[i],确保计算正确。

459.重复的子串

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

class Solution { // 暴力解法
public:
    bool repeatedSubstringPattern(string s) {
        int n = s.size();
        int j = 0;
        bool match;
        for (int i = 1; 2 * i <= n; i++) {
            for (int j = i; j < n; j++) {
                if (n % i == 0) {
                    match = true;
                    if (s[j] != s[j - i]){
                        match = false;
                        break;
                    }
                }
            }
            if (match)
            return true;
        }
        return false;

    }
};

看s能否由长度为1,2,3...n/2个字符组成

s[j] == s[j - i] 是为了验证字符串是否具有周期性,即能否由长度为 i 的子串重复构成。

j就直接从i开始,如果从0开始,一是没有必要,二是会访问到【0-i】会是负数

class Solution {//移动匹配算法
public:
    bool repeatedSubstringPattern(string s) {
        return (s+s).find(s,1) != s.size();
    }
};

我靠,这个思路有点太牛了,就是把字符串拼接起来,如果字符串有子串,中间就能找到这个字符串

但如果是abc abc,就找

【1,3】:bca

【2,4】:cab

【3,5】:abc就等于s.size()了,返回false,就很妙

class Solution {//KMP算法
public:
    void getNext(vector<int>& next, const string& s) {
        next[0] = 0;
        int j = 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;
        }
    }
    bool repeatedSubstringPattern(string s) {
        if (s.size() == 0)return false;
        vector<int> next(s.size());
        getNext(next, s);
        int len = s.size();
        
        if (next[len - 1] != 0 && len % (len - next[len - 1]) == 0){
            return true;
        } // 必须要next[len - 1] != 0,因为如果没有相同前后缀肯定也没有相同子串构成
        return false;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值