Leetcode28、实现strStr()

一、题目

实现 strStr() 函数。

给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。

示例1
输入:haystack = “cad”, needle = “cc”
输出:-1

示例2
输入:haystack = null, needle = “mn”
输出-1

示例3
输入:haystack = “mhdkn”, needle = null
输出:0

说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/implement-strstr
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、代码实现

1)双指针滑窗法

如图:开始时初始化滑窗,然后滑窗逐渐右移直到数组末端
在这里插入图片描述

class Solution {
    public int strStr(String haystack, String needle) {
    if(haystack==null||(needle!=null&&haystack.length()<needle.length()))return -1;
    if(needle==null)return 0;
    int i=0;//滑窗左指针
    int j=needle.length()-1;//滑窗右指针
    for(;j<haystack.length();j++) {
    	if(haystack.substring(i, j+1).equals(needle))
    		return i;
    	i++;
    }
    return -1;
    }
}

时间复杂度是O((N-L)L)=O(NL),其中N是haystack的长度,L是needle的长度。

if中的条件可以简化
if(haystack==null||(needle!=null&&haystack.length()<needle.length()))return -1;
改成
if(haystack==null)return -1;也是可以的,简单的去判断比较难判断出这两种的优劣。

2)next预处理数组实现的KMP

haystack数组不走回头路,时间复杂度O(N+L)

                             问?

时间复杂度为什么会是O(N+L),难道不应该是O(N)吗

核心代码是求next数组的那五行代码

class Solution {
    public int strStr(String haystack, String needle) {
   if (haystack == null)
			return -1;
		if (needle == null||needle.length()==0)
			return 0;
		int[] next = new int[needle.length() + 1];
		getNext(needle.toCharArray(), needle.length(), next);
		int j = 1;// j为needle中的指针,i为haystack中的指针
		boolean mark=false;
		for (int i = 0; i <haystack.length(); i++) {
			if(mark) {i--;mark=false;}
			if (haystack.charAt(i) == needle.charAt(j - 1))
				j++;
			else {
				j = next[j] != 0 ? next[j] : 1;
				if(j!=1||needle.charAt(0)==haystack.charAt(i))mark=true;
			}
			if (j == needle.length() + 1)
				return i - needle.length() + 1;
		}
		return -1;
    }
    
	private static void getNext(char[] needle, int length, int[] next) {
		// TODO Auto-generated method stub
		next[1] = 0;
		int i = 1, j = 0;
		while (i < needle.length) {
			if (j == 0 || needle[i - 1] == needle[j - 1]) {
				next[++i] = ++j;
			} else
				j = next[j];
		}
	}
}

刚学KMP,代码是第一次缝缝补补改出来的代码,strStr(String haystack, String needle)中还是比较冗余,有空的时会会更新优化代码。

注:像KMP这样常用的方法,其实可以封装在一个类中,这样下次使用就可以直接用这个接口了,以此来减少重复的代码

3)米利状态机实现的KMP

相比于2,在本质上仍然是通过预处理数组让字符串匹配具有了"记忆"功能,不需要傻瓜式的重复去匹配,时间复杂度和空间复杂度和next指针处理一样。个人觉得米利状态机实现的KMP是更容易理解的,有空的时候会把详细文字描述补上来。

class Solution {
    public int strStr(String haystack, String needle) {
		if (haystack == null)
			return -1;
		if (needle == null||needle.length()==0)
			return 0;
		int M = haystack.length();
		int N = needle.length();
		int[][] dp = new int[N][256];
		initialDq(dp, needle);
		int j = 0;
		for (int i = 0; i < M; i++) {
			j = dp[j][haystack.charAt(i)];
			if (j == N)
				return i - N + 1;
		}
		return -1;
	}

	private static void initialDq(int[][] dp, String needle) {
		// TODO Auto-generated method stub
		int X = 0;// 镜像位置
		dp[0][needle.charAt(0)] = 1;
		for (int j = 1; j < needle.length(); j++) {
			for (int c = 0; c < 256; c++) {
				dp[j][c] = dp[X][c];// 状态重启
				dp[j][needle.charAt(j)] = j + 1;// 可以直接进一步的状态不用重启
			}
			X = dp[X][needle.charAt(j)];
		}
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值