在2018的最后一个工作日,刷到leetcode上的一道关于字符串类型的题,题目是这样的:
--------------------------------------------------------------------------------------------------------------------------------------
实现 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() 定义相符。
-----------------------------------------------------------------------------------------------------------------------------------------
看到题目的第一反应,这不是indexOf就搞定了嘛,抱着皮一下很开心的原则,我输入了以下答案:
return haystack.indexOf(needle);
果然通过,并且查看运行时间只有4ms,emmmmm,那我要自己写一个来看看,于是又有了以下的答案:
/*
1)先判断needel是否为空字符串;
2)然后再比较这两个串是否完全相等
3)从haystack的开头开始取出和needle大小相当的字串进行比较,找到第一个相等的则返回当前index
4)上述条件都不符合则表示needel不是haystack的字串,返回-1
*/
public int strStr(String haystack,String needle){
if(needle.length()==0){
return 0;
}
if(haystack.equals(needle)){
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;
}
But,我写的这个东西,它的运行时间是7ms,emmmmm,在强烈好奇心的驱使下,我准备看看indexOf是怎么做的,以前都是“哎这个好用,哎那个也好用”,从2019年起我要做一个知其所以然的好青年,嘻嘻。
打开String.java类,找到indexOf(String str),是这样的:
/**
* 返回字符串中字串str第一次出现的位置。
* @param str 是需要寻找的字串
* @return 字串第一次出现的位置,如果字串没有出现,则返回-1
*
*/
public int indexOf(String str) {
return indexOf(str, 0);
}
这个函数return了indexOf(str,0),就是indexOf方法的重载:
int indexOf(String str, int fromIndex):从指定索引处寻找子串出现的第一个位置。
那我们就接着看indexOf(String str, int fromIndex)的源码是怎么做的:
/**
* 从指定索引处开始寻找,返回子串在字符串中第一次出现的位置
* @param str 子串
* @param fromIndex 指定开始寻找的位置
* @return 从指定位置处开始寻找,返回子串第一次出现的位置,如果找不到,则返回-1
*/
public int indexOf(String str, int fromIndex) {
return indexOf(value, 0, value.length,
str.value, 0, str.value.length, fromIndex);
}
emmmmm,又是调用了一个重载的indexOf函数,那就接着往下找呗:
/**
* 这是String 和 StringBuffer 用来进行搜索的代码,源是要搜索的字符数组(character array)
* 目标是被搜索的字符串
* @param source 被搜索的字符数组(源)
* @param sourceOffset 字符串源的偏移
* @param sourceCount 字符串源的长度
* @param target 被搜索的字符数组(目标)
* @param targetOffset 目标字符串的偏移
* @param targetCount 目标字符串的长度
* @param fromIndex 开始进行搜索的索引
*/
static int indexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount,
int fromIndex) {
if (fromIndex >= sourceCount) {//如果开始的索引大于源字符串的长度
//如果目标字符串长度为0,则返回源字符串的长度,否则返回-1
return (targetCount == 0 ? sourceCount : -1);
}
if (fromIndex < 0) {//如果起始索引小于0,则设置起始索引为0,从源的开始处进行查找
fromIndex = 0;
}
if (targetCount == 0) {
//如果目标字符串长度为0(空串),则返回指定的索引,空串当然在哪个位置都是匹配的嘛
return fromIndex;
}
char first = target[targetOffset];//取目标的偏移量位置的字符
int max = sourceOffset + (sourceCount - targetCount);//计算最多需要遍历到源的位置
// i 初值取源偏移+指定索引,表示从源的哪个位置开始匹配
// i 应当取到max位置为止
for (int i = sourceOffset + fromIndex; i <= max; i++) {
/* Look for first character. */
if (source[i] != first) {//将目标的第一个字符与源进行匹配
//在max范围内去寻找第一个字符匹配的位置,
//如果没有,这个for就结束了,返回最后的-1表示没找到
while (++i <= max && source[i] != first);
}
/* Found first character, now look at the rest of v2 */
if (i <= max) {
//j 表示源与目标第一个字符匹配位置的下一个位置
int j = i + 1;
//end 表示匹配停止的位置,也就是从j往后 targetCount-1个位置
//(target Count-1表示剩下需要匹配的字符
int end = j + targetCount - 1;
//k 表示从target开始匹配的位置
for (int k = targetOffset + 1; j < end && source[j]
== target[k]; j++, k++);
//找到了子串
if (j == end) {
/* Found whole string. */
return i - sourceOffset;
}
}
}
return -1;
}
到这里已经明白了,有一点就是,在这里其实都是操作字符数组进行的,所以在调用String的这些方法时,其实是转换成数组在进行操作。这和我自己写的那个其实有一点相似,都是按位置比较子串,但我还是用了人家的substring方法(我懒,要不要待会再看看substring的源码?LOL)
那我们根据indexOf的思想来写一个看看:
public int mystrStr(String haystack,String needle){
char[] source = haystack.toCharArray();
char[] target = needle.toCharArray();
int sourceCount = source.length;
int targetCount = target.length;
if(targetCount == 0){
return 0;
}
char first = target[0];
int max = sourceCount-targetCount;
for(int i = 0;i<=max;i++){
if(source[i] != first){
while(++i<=max && source[i] != first);
}
if(i<=max){
int j = i+1;
int end = j + (targetCount-1);
for(int k = 1;j
山寨版登场,其实也没差多少,然后我们去提交看看:
都差不多嘛,好的我佛了。但是我比第一个7ms的时候更有知识了哦嘻嘻。