【LeetCode刷题记录】简单篇-28-找出字符串中第一个匹配项的下标

【题目描述】

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回  -1 


【测试用例】

示例1:

        输入:haystack = "sadbutsad",needle = "sad"

        输出:0

        解释:"sad"在下标0和6处匹配。第一个匹配项的下标是0,所以返回0。

示例2

        输入:haystack = "leetcode",needle = "leeto"

        输出:-1

        解释:"leeto"没有在"leetcode"中出现,所以返回-1。


【思路分析】

这道题是经典的字符串匹配问题:即在主串寻找子串,如果存在子串则返回子串在主串中的起始位置,如果不存在则直接返回-1。给出两种解法。

法一:简单暴力法

        这种方法是大部分人第一时间都能想到的方法。简单直接,索引 i 用于遍历主串haystack,索引 j 用于遍历子串needle,均从串起始位置0开始:

如果haystack[i] == needle[j],则两个索引都后移继续比较下一个位置;

如果haystack[i] != needle[j],则 i = i - j + 1(主串指针回退到本轮匹配起始位置的下一个位置),j = 0(子串指针回退到起始位置)。

循环结束后,如果子串指针 j 与子串长度相等,说明匹配成功(因为j就表示子串中前j个元素匹配成功),返回 i - j ,即为子串在主串中的起始位置。

否则直接返回-1。

法二:KMP算法

        KMP算法是字符串匹配这一问题中的神级算法,据我所知至今没人能对这个算法再进行改进。所以它的代码也很固定,记住就行(反正我是记不住,考研的时候学了几遍都理解不了它的代码为什么可以这么简洁!),不过理解KMP的原理才是最重要的,因为它的代码固定,所以不记得代码的时候网上一搜就可以,原理才是根本

        KMP和法一的本质区别就在于在 haystack[i] != needle[j] 时,i 不用回退,而 j 也不用每次都回退到0,具体退到何处由next数组确定,next数组是KMP的核心

        具体的KMP原理读者可以自行搜索查阅,如果写在这里篇幅太大(其实是本人水平有限,不一定能给你讲懂哈哈哈)。

ps:KMP代码的优越性体现在主串子串很长的情况下,像这一类题目的测试用例我想应该都不会很长,所以在LeetCode提交后这两种方法的差距体现不出来。如图所示:

法一C实现:

法一C++实现:

法二C实现:


【参考代码】

法一:C实现

#include <stdio.h>
#include <string.h>

//easy-28-找出字符串中第一个匹配项的下标
int strStr(char* haystack, char* needle);

int main(){
	char *haystack, *needle;
	scanf("%s",haystack);
	scanf("%s",needle);
	int res = strStr(haystack, needle);
	printf("%d\n",res);
	return 0;
} 

int strStr(char* haystack, char* needle){
	int i=0,j=0;
    while(i<strlen(haystack) && j<strlen(needle)){
    	if(haystack[i] == needle[j]){
    		i++;
    		j++;
		}else{
			i = i - j + 1;
			j = 0;
		}
	} 
	if(j == strlen(needle)){
		return i-j;
	}
	return -1;
}

法一:C++实现

#include <iostream>
#include <string> 
using namespace std;

//easy-28-找出字符串中第一个匹配项的下标
class Solution {
public:
    int strStr(string haystack, string needle);
};

int Solution::strStr(string haystack, string needle){
	int i=0, j=0;
	while(i<haystack.size() && j<needle.size()){
		if(haystack[i] == needle[j]){
			i++;
			j++;
		}else{
			i = i - j + 1;
			j = 0;
		}
	}
	if(j == needle.size()){
		return i-j;
	}
	return -1;
} 

int main(){
	string haystack, needle;
	cin>>haystack;
	cin>>needle;
	Solution sol;
	int res = sol.strStr(haystack, needle);
	cout<<res<<endl;af
	return 0;
}

法二:C实现

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//easy-28-找出字符串中第一个匹配项的下标
int strStr(char* haystack, char* needle);

int main(){
	char *haystack, *needle;
	scanf("%s",haystack);
	scanf("%s",needle);
	int res = strStr(haystack, needle);
	printf("%d\n",res);
	return 0;
} 

int strStr(char* haystack, char* needle){
	int i=0, j=-1;
	int *next = (int*)malloc(sizeof(int)*(strlen(needle)+1));
	next[0] = -1;
	//求next数组 
	while(i<strlen(needle)){
		if(j==-1 || needle[i]==needle[j]){
			++i;
			++j;
			next[i] = j;
		}else{
			j = next[j];
		}
	}
	//KMP主体 
	i=0;
	j=0;
	int len1 = strlen(haystack);
	int len2 = strlen(needle);
	while((i<len1) && (j<len2)){
		if(j==-1 || haystack[i]==needle[j]){
			++i;
			++j;
		}else{
			j = next[j];
		}
	} 
	if(j == strlen(needle)){
		return i-strlen(needle);
	}
	return -1;
} 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值