实现strStr()
题目描述
示例 1:
输入: haystack = "hello", needle = "ll"
输出: 2
示例 2:
输入: haystack = "aaaaa", needle = "bba"
输出: -1
说明:
当needle
是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当needle
是空字符串时我们应当返回 0 。这与C语言的strstr()
以及 Java的indexOf()
定义相符。
解题思路
个人AC
声明两个游标hc
和nc
:
hc
即haystack cursor
,用来辅助遍历字符串haystack
;nc
即needle cursor
,用来辅助遍历字符串needle
。
class Solution {
public int strStr(String haystack, String needle) {
int hc = 0, nc = 0; // c即cursor,用来辅助遍历字符串
int hLen = haystack.length(), nLen = needle.length();
if (hLen < nLen) return -1;
if (hLen == 0 && nLen == 0) return 0;
while (hc < hLen) {
int hRestC = hc;
while (hRestC < hLen) {
if (nc == nLen) return hc;
char cOfH = haystack.charAt(hRestC), cOfN = needle.charAt(nc);
if (cOfH == cOfN) {
hRestC++;
nc++;
} else {
hc++;
nc = 0;
break;
}
}
}
return -1;
}
}
时间复杂度: O ( n 2 ) O(n^2) O(n2);
空间复杂度: O ( 1 ) O(1) O(1)。
最优解
Sunday
Sunday匹配机制
- 目标字符串:
haystack
或target
; - 模式串:
needle
或pattern
; - 当前查询索引:
idx
(初始为0); - 待匹配字符串:
target.substring(idx, idx + pattern.length())
。
每次匹配都会从目标字符串中提取待匹配字符串与模式串进行匹配:
-
如果匹配,则返回
idx
; -
若不匹配,则查看待匹配字符串的后一位字符
c
:- 若
c
位于模式串中,则idx = idx + 偏移表[c]
; - 否则,
idx = idx + pattern.length() + 1
;
重复上述过程,直到
idx + pattern.length() > target.length()
。 - 若
偏移表
偏移表的作用是存储每一个在模式串中出现的字符和其对应的偏移位(该字符在模式串中出现的最右位置到尾部的位置 + 1),如**模式串aab
**的偏移表为:
a
的偏移位为pattern.length() - i = 3 - 1 = 2
;b
的偏移位为pattern.length() - i = 3 - 2 = 1
;- 其它均为
pattern.length() + 1 = 3 + 1 = 4
。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7j22GM50-1573103113502)(assets/1573100111625.png)]
举例
target = checkthisout
,pattern = this
。
S1:
idx = 0
,待匹配字符串 =chec
;- 因为
chec != this
,所以查看chec
下的后一个字符k
是否在pattern
中(查看偏移表), k
不在偏移表中,所以idx = idx + 1
。
S2:
idx = 5
,待匹配字符串 =this
;- 因为
this = this
,所以返回idx = 5
。
实现
class Solution {
public int strStr(String haystack, String needle) {
int hLen = haystack.length(), nLen = needle.length();
if (hLen < nLen) return -1;
if (nLen == 0) return 0;
// 计算偏移表
HashMap<Character, Integer> shift = getShiftMap(needle);
int hc = 0; // 即idx
while (hc + nLen <= hLen) {
// 待匹配字符串
String subH = haystack.substring(hc, hc + nLen);
// 判断是否匹配
if (subH.equals(needle)) {
return hc;
} else {
// 边界处理
if (hc + nLen >= hLen) return -1;
// 判断待匹配字符串的下一个字符是否在偏移表中
char c = haystack.charAt(hc + nLen);
if (shift.containsKey(c)) {
hc += shift.get(c);
} else {
hc += nLen + 1;
}
}
}
return hc + nLen >= hLen ? -1 : hc;
}
private HashMap<Character, Integer> getShiftMap(String pattern) {
HashMap<Character, Integer> shift = new HashMap<>();
for (int i = 0; i < pattern.length(); i++) {
char c = pattern.charAt(i);
shift.put(c, pattern.length() - i);
}
return shift;
}
}
时间复杂度:
O
(
n
)
O(n)
O(n),最坏情况为
O
(
m
∗
n
)
O(m * n)
O(m∗n),其中n
为目标串target
的长度,m
为模式串pattern
的长度;
空间复杂度: O ( n ) O(n) O(n)。