【题目】
实现 strStr() 函数。
给定一个haystack字符串和一个needle字符串,在haystack字符串中找出needle字符串出现的第一个位置
(从0开始)。如果不存在,则返回 -1。
示例 1:
输入: haystack = "hello", needle = "ll"
输出: 2
示例 2:
输入: haystack = "aaaaa", needle = "bba"
输出: -1
【说明】:
当needle是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当needle是空字符串时我们应当返回0。这与C语言的strstr()以及Java的indexOf()定义相符。
【解法一】(暴力解法)算法时间复杂度O(mn)
//此方法时间复杂的高,执行时间长,但容易想到
//74 / 74 个通过测试用例。执行用时:2470 ms。内存消耗:38 MB。
class Solution {
public int strStr(String haystack, String needle) {
int a=haystack.length();
int b=needle.length();
//边界条件
if(haystack==null||a<b)return -1;
if(needle==null||b==0)return 0;
for(int i=0;i<a;i++){
//进入循环条件:在大字符串中发现了,小字符串零号索引位置的元素
if(haystack.charAt(i)==needle.charAt(0)){
//记录往右走多长
int len=0;
//当大字符还没走到头,同时小字符串没走到头,同时大字符串与小字符串当前位置相同
while(i+len<a&&len<b&&haystack.charAt(i+len)==needle.charAt(len)){
len++;
}
//如果len等于小字符串长度,说明匹配成了,返回出现的第一个位置
if(len==b)return i;
}
}
return -1;
}
}
【解法二】
//return一个三元运算符表达式结果,利用Java indexOf方法,内置库函数,是算法最优解,执行效率高,
//不过这么写对于刷题和算法训练来讲没有什么意义。74 / 74 个通过测试用例。执行用时:0 ms
//0毫秒的用时秒杀一切手写算法
public int strStr(String haystack, String needle) {
return haystack.indexOf(needle) >= 0 ? haystack.indexOf(needle) : -1;
}
【解法三】 kMP算法:
讲义链接https://web.stanford.edu/class/cs97si/10-string-algorithms.pdf
斯坦福KMP算法讲义
动态规划之 KMP 算法详解
//KMP算法的思路就是找到搜索串每个字符之前可以免匹配的最大长度,比如搜索串 abaabb 匹配到最后一个
//字符不匹配,则前面可免匹配的部分为 ab ,从第三个字符开始继续,减少重复无意义的工作。
class Solution {
public int strStr(String t, String p) {
//t是被查找的haystack区域,p是要在heystack区域中查找的needle字符串
int n=t.length();
int m=p.length();
if(m==0) return 0;
//pi就是斯坦福KMP讲义中的π,它就是求p里面的共同前缀与后缀
int[] pi=new int[m];
computrPrefix(p,pi);//求解π Table的函数,讲义第11页
int k=-1;
//Pattern Matching Implementation
for(int i=0;i<n;i++){ //KMP,MATCHER
while(k>=0 && p.charAt(k+1) != t.charAt(i)){
k=pi[k]; //next character does not match
}
if(p.charAt(k+1) == t.charAt(i)){
k++; //next character matches
}
if(k==m-1){
return i-m+1;
}
}
return -1;
}
//π Table Implementation
private void computrPrefix(String p,int[] pi){
//参见算法导论中Chapter32 String Matching中COMPUTE-PREFIX-FUNCTION
//求pi数组的伪代码(page1006,英文版)
pi[0] = -1;
int k = -1;
int m = p.length();
for(int i = 1;i < m ;i++){
while (k >= 0 && p.charAt(k+1) != p.charAt(i)){
k = pi[k];
}
if(p.charAt(k+1) == p.charAt(i)){
k++;
}
pi[i] = k;
}
}
}
//74 / 74 个通过测试用例。状态:通过。执行用时:9 ms 内存消耗:39.4 MB
//对比发现执行时间大约比暴力解法快250倍