implement strStr()
Implement strStr()
Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
Clarification:
What should we return when needle is an empty string? This is a great question to ask during an interview.
For the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C’s strStr() and Java’s indexOf().
今天这道题呢,又是一个简单难度的,是让我们实现类似C中的strStr()方法或者Java中的indexOf()方法,也就是找出给定的子串在目标字符串中第一次出现的索引。
咦,indexOf()?这个我熟,那我先试试这样
/**
* @author: LittleWang
* @date: 2021/4/20
* @description:
*/
public class Solution {
public int strStr(String haystack, String needle) {
return haystack.indexOf(needle);
}
}
(投机取巧)提交!
哎?这……咳咳,我们这是投机取巧,当然不建议使用了,毕竟刷题的主要目的是学习嘛,这样就没有意思了。
我们还是自己来好好想一想,这种算法应该怎么实现。
我首先想到的就是非常简单粗暴的,遍历法,用两重循环来遍历两个字符串。这里我使用了Java的startsWith()方法,基本思路如下:
定义一个索引index,用来遍历haystack,判断以每个字符开头的子串是不是以needle开头,如果是,那就返回这个index的值,否则就继续向后遍历。如果没有找到满足条件的index,那就返回-1。代码如下:
/**
* @author: LittleWang
* @date: 2021/4/20
* @description:
*/
public class Solution2 {
public int strStr(String haystack, String needle) {
if(needle.isBlank())
return 0;
for (int index = 0; index < haystack.length(); index++) {
if(haystack.substring(index).startsWith(needle)) {
return index;
}
}
return -1;
}
}
这其实本质上来说就是简单的遍历,我只是换了一种表达的形式而已,效率比起Java自带的IndexOf方法就差一些了。
那我们来看看Java中String类的indexOf方法的源码是怎么实现的吧。
说实话,Java中的String类有一点复杂,我并不是完全看得懂,根据自己读的源码,在它的基础上做了一点点简化,加上了自己的理解,主要是为了突出indexOf这个方法的实现,别的方法细节也是能省则省了。
/**
* @author: LittleWang
* @date: 2021/4/20
* @description:
*/
public class String{
private final char value[]; //String类的底层实际上是维护了一个不可变的字符串数组
public String(char[] str) { //构造函数是我自己加上的,实际不是这样实现的
value = str;
}
public int indexOf(String str) { //入口函数
return indexOf(str, 0);
}
public int indexOf(String str, int fromIndex) { //这是Java中indexOf的另一个重载实现,在使用上一个方法的时候实际是调用了该方法
return indexOf(value, value.length, str, fromIndex);
}
static int indexOf(char[] source, int sourceCount,
String target, int fromIndex) { //最终实现在这里
char[] tgt = target.value;
int tgtCount = tgt.length;
if(fromIndex >= sourceCount) { //检查所有的特殊情况
return tgtCount == 0 ? 0 : -1;
}
if(fromIndex < 0) {
return 0;
}
if(tgtCount == 0) {
return fromIndex;
}
if(tgtCount > sourceCount) {
return -1;
}
char first = tgt[fromIndex]; //目标字符串的第一个字符
int max = sourceCount - tgtCount; //如果索引大于max,target就必不可能在source中出现了,因为target剩余的长度已经小于target的长度了
for(int i = fromIndex; i <= max; i++) {
//找到满足第一个字符相等的位置
if(source[i] != first) {
while(++i <= max && source[i] != first)
;
}
if(i <= max) {
int j = i + 1;
int end = j + tgtCount - 1;
for(int k = 1; j < end && source[j] == tgt[k]; j++, k++)
;
//只有当判断的字符全都一样时,最终j的值才会等于end,否则循环会提前结束,说明target不匹配
if(j == end) {
return i;
}
}
}
return -1;
}
}
嗯,差不多了,今天的每日一题就到这里了,关于源码我可能没有把思路讲清楚,先在这立个flag吧,我后面会读懂String类的所有源码,并把所有的实现思路整理出来放在博客里。