代码随想录算法训练营第九天|28. 实现 strStr()、459.重复的子字符串、字符串总结、双指针回顾

本文详细介绍了如何使用KMP算法实现strStr函数,通过计算前缀表在字符串匹配过程中提高效率,并探讨了如何用KMP算法解决LeetCode中的459题重复子字符串问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:28. 实现 strStr()

文章链接:代码随想录

视频链接:LeetCode:实现strStr

题目链接:力扣题目链接

详解:KMP:主要应用于字符串匹配,当出现字符串不匹配是,可以知道一部分之前已经匹配的文本内容,利用该信息避免从头再做匹配

当匹配到字符串'f'不匹配时,退回到下标为2的位置开始匹配,不用重新从小标为0的位置开始匹配

前缀:不包含末尾元素的顺序组成,eg: aabaaf的前缀为a、aa、aab、aaba、aabaa 

后缀:不包含首元素的顺序组成,eg: aabaaf的后缀为f、af、aaf、baaf、abaaf

前缀表:记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配,记录小标i之前(包括i)的字符串中,有多大长度的相同前缀后缀

class Solution {
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[j] != s[i]) { // 要确保j-1>=0,所以对j进行一个限制
			j = next[j - 1]; //找前一位对应的回退位置
		}
		// 前后缀相等的情况
		if (s[j] == s[i]) {
			j++; // 如果相同进行加1
		}
		next[i] = j; // 赋值前缀表
	}
}
// 实现 strStr()
int strStr(string haystack, string needle) {
	// needle为需要匹配的字符串,计算该字符串的前缀表
	if (needle.size() == 0) return 0;
	vector<int>next(needle.size()); //初始化
	getNext(next, needle); //获得前缀表
	// 开始进行匹配,跟获得前缀表差不多
	int j = 0;
	for (int i = 0; i < haystack.size(); i++) { //不同点在于,两个字符串进行匹配时从0开始
		// 不匹配的情况
		while (j > 0 && needle[j] != haystack[i]) {
			j = next[j - 1]; // 回退
		}
		if (needle[j] == haystack[i]) {
			j++;
		}
		// 这里与getNext不用,不用构建前缀表,如果满足,直接返回
		if (j == needle.size()) {
            // 当j == needle.size(),i还没++
			return (i - needle.size()+1);
		}
	}
	return -1;
}
};

题目:459.重复的子字符串

文章链接:代码随想录

视频链接:LeetCode:459.重复的子字符串

题目链接:力扣题目链接

图释:

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[j] != s[i]) { // 要确保j-1>=0,所以对j进行一个限制
			j = next[j - 1]; //找前一位对应的回退位置
		}
		// 前后缀相等的情况
		if (s[j] == s[i]) {
			j++; // 如果相同进行加1
		}
		next[i] = j; // 赋值前缀表
	}
}
// 重复的子字符串
bool repeatedSubstringPattern(string s) {
	// 通过计算最大前缀表来得到
	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;
	}
	return false;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值