LeetCode第28题思悟——strStr(implement-strstr)

LeetCode第28题思悟——strStr(implement-strstr)

知识点预告

  1. 注意算法的使用场景和优劣分析;
  2. 参数边界条件的处理

题目要求

给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
链接:https://leetcode-cn.com/problems/implement-strstr
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

示例

示例 1:

输入: haystack = “hello”, needle = “ll”
输出: 2
示例 2:

输入: haystack = “aaaaa”, needle = “bba”
输出: -1
说明:

当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。

对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。

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

我的思路

作为一道简单题,这道题可以甚至可以直接通过Java String类提供的API完成,需要注意的是参数特殊情况的处理,比如空字符串和null;

但是在这里,说到底该题是字符串之间的匹配问题,所以我尝试使用了KMP算法,关于KMP算法可以参见我的这篇博文:KMP字符串匹配算法思悟;内容很详实;

但是,实际运行效果怎么样呢?不好,倒不是算法不好,而是算法应用的场景不匹配;具体的原因我会在差异分析一节中详细反思

public int strStr(String haystack, String needle) {
	if(needle==null||needle.trim().equals("")){
		return 0;
	}
	return match(needle,haystack);
}
private int[] getMoveInfo(char[] pattern) {
	int m = pattern.length;
	int[] info = new int[m];
	int matchedNum = 0;
	for (int i = 1; i < m; i++) {
		while (matchedNum > 0 && pattern[matchedNum] != pattern[i]) {
			matchedNum = info[matchedNum - 1];
		}
		if (pattern[matchedNum] == pattern[i]) {
			matchedNum++;
		}
		info[i] = matchedNum;
	}
	return info;
}
public int match(String pattern, String source) {
	int patternLength = pattern.length();
	int sourceLength = source.length();
	char[] p = pattern.toCharArray();
	char[] s = source.toCharArray();
	int[] moveInfo=getMoveInfo(p);
	int matchedNum = 0;
	int patternBorder = patternLength - 1;
	for (int i = 0; i < sourceLength; i++) {
		while (matchedNum > 0 && p[matchedNum] != s[i]) {
			matchedNum = moveInfo[matchedNum - 1];
		}
		if (p[matchedNum] == s[i]) {
			matchedNum++;
		}
		if (matchedNum == patternLength) {
			return (i - patternBorder);
		}
	}
	return -1;
}

优秀解法

//解法A
public int strStr(String haystack, String needle){
	return haystack.indexOf(needle);
}
//解法B
public int strStr(String haystack, String needle) {
	if(needle.equals(""))return 0;
	for (int i=0;i<=haystack.length()-needle.length();i++){
		if (haystack.substring(i,i+needle.length()).equals(needle)){
			return i;
		}
	}
	return -1;
}
//解法C
public int strStr(String haystack, String needle) {
	if(needle.equals("")){
		return 0;
	}
	char[] h = haystack.toCharArray();
	char[] n = needle.toCharArray();
	for (int i = 0; i < h.length-n.length+1; i++) {
		if(h[i]==n[0]){
			int j=1;
			for (;j<needle.length();j++){
				if(h[i+j]!=n[j]){
					break;
				}
			}
			if(j==needle.length()){
				return i;
			}
		}
	}
	return -1;
}

差异分析

解法A为最简解法,充分利用语言特性,但是谈不上什么算法技巧;

解法B不断截取子串,然后和查询值作对比,倒也是一种思路,但是略显繁琐;

解法C则为常规解法,思路明确;

以上即为与题目要求相符合的解法;那么经典的KMP算法,为什么效率上反倒不如这几种算法呢?答案是:场景不合适;

KMP算法的核心分为两步:第一步是模式字符串的自匹配,在这道题中即为needle字符串;第二步则是模式字符串和待匹配字符串的匹配;我们这道题实际上只需要第2步;进行第一步的目的是为了优化第二步;

然鹅,这道题只是要求找出首次出现位置;而KMP发挥作用的场景应该是找出所有出现的位置;如此,第一步的额外代价才能在第二步中得到弥补,从而提高字符串匹配的效率;也就是说,我们付出了代价,却没有收获的机会;总而言之,这里有一点点大材小用,却没用好的味道;

另外,这道题的重点在于对needle的边界条件的考虑:needle为空字符串;好在题目也是给出了提示;但是面试官不会啊;所以要重视参数的边界条件

解法A就没有问题了吗?如果haystack为null会怎样呢?我认为应该处理一下这种情况的,但还是既然能通过测试,一定程度上也说明无需考虑这种情况,但在实际开发中,还是“不要相信用户的输入”比较好;

知识点小结

  1. 注意算法的使用场景和优劣分析;
  2. 参数边界条件的处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值