LeetCode刷题-28.实现strStr()
题目链接:28.实现strStr()
¶题解:
嗯,使用暴力就是简单题!
提高效率使用KMP,复杂了,好好理解,多实现,最好记住模板!本题就是一个模板。
¶题目简述:
给定两个字符串,从第一个中找第二个串,能找到返回起始下标,找不到返回-1,第二个串为空,直接返回0。
¶题解一:暴力
直接扫描一遍原串即可:
- 先判断当前位置是否够子串的长度,不够直接返回-1,因为肯定没有可以匹配的。
- 如果位置长度够,就从当前位置截取和子串长度相同,查看是否相等,相等直接返回当前下标
i
,否则继续下次循环
时间复杂度:substr(pos, m)
:复杂度为O(len),总时间复杂度为O(n*m)
¶AC代码一:
1 |
|
¶题解二:KMP
为了弄明白KMP算法,我也是盯着看,画着图搞了一上午!
这也是一个模板题,需要记下来并掌握代码的实现及理解该算法的运行流程!
时间复杂度: O(n + m)
为了方便,这里将字符串都从1开始!
1 |
|
KMP
算法的核心就是一个next
数组:
next
数组的作用:若没有该数组,后续匹配过程中出现不匹配的话,需要将起始位置后移一位,重新开始一一匹配,但是有了该数组,就不一定是移动一位了,而是移动尽可能多的位置,使得前j
个字符和原串仍然匹配,只需判断第j + 1
个字符即可!
首先搞清楚next数组存储的东西是什么?
next[i]:
所有s[1]-s[i]
中前缀等于后缀的最大长度(特指非平凡前缀和后缀)
非平凡:指的是不包括自己,eg:abc
中的next[3]
不能为3,应该为0。
举个例子:
举个例子:abcdefghabcd
中,next[12]
就应该为4,即前缀和后缀相等的最大长度,为前缀abcd
和后缀abcd
匹配时的值。
下一个问题,怎么求next数组?
首先,next[0]
不需要管,下标从1开始,next[1] = 0
,非平凡不包括自己!
从下标为2开始即可!
假设当前状态如下:i - 1
为原串p
指向的位置,j
为p
的前缀后缀相等时前缀的尾。序号1和序号2是同一段,序号3是原串1 ~ (i - 1)
中与前缀相等的后缀,此时序号1,2,3都是相等的。
若 i
和 j + 1
可以匹配,此时next[i]
就会由j
变为j + 1
,则效果图如下:
若 i
和 j + 1
无法匹配,则说明前缀串1 ~ j
无法满足当前next[i]
的条件,此时j
的位置就需要发生变化,将前缀缩小为1 ~ next[j]
去试探此时是否可以匹配next[i]
的条件,若一直无法匹配,已经到了next[1] = 0
或j == 0
时,仍然无法匹配,则当前next[i] = 0
;若试探中,某次可以匹配,则当前next[i]
的值就可以更新为当前next[j] + 1
会发现后面的next
计算都在前面已经算出来的基础上进行试探的,而前面算出来的都是前后缀相等且最长的,所以这样可以求得所有next
数组的值,且一定是正确的!
下一个问题,怎么求子串与原串的匹配并计算得到起始下标?
和求解next
数组一样,求解next
数组是用的两个待匹配字符串p
,求下面这个问题则只需要将第一个串换成s
串即可,最后只需要判断什么时候等于待匹配字符串的长度,直接计算返回该下标即可!
什么时候就算找到了?
当然是当j == m
的时候,即说明此时已经匹配完了p
串。
最终返回的长度就是i - m
,即s
串的匹配终点的前m个字符的位置,应该为i - m + 1
,但是我们下标是从1开始,所以要减去1,i - m + 1 - 1
即i - m
。
注意:需要特判p
串为空的情况,需要返回0。
¶AC代码二:
1 |
|