文章目录
- 问题描述
- 示例1
- 示例2
- 提示
- 思路分析
- 代码分析
- 完整代码
- 详细分析
- 运行效果截图
- 调用示例
- 运行结果
- 完结
问题描述
给你两个字符串
haystack
和needle
,请你在haystack
字符串中找出needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果needle
不是haystack
的一部分,则返回 -1
示例1
输入:haystack = “sadbutsad”, needle = “sad”
输出:0
解释:“sad” 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。
示例2
输入:haystack = “leetcode”, needle = “leeto”
输出:-1
解释:“leeto” 没有在 “leetcode” 中出现,所以返回 -1 。
提示
- 1 <= haystack.length, needle.length <= 104
- haystack 和 needle 仅由小写英文字符组成
思路分析
在解决这个问题时,可以采用双指针的思路。首先,我们将两个指针分别指向
haystack
和needle
的起始位置。然后,我们开始遍历haystack
字符串,比较当前指针位置处的字符是否与needle
字符串中的字符相同。如果相同,我们就继续比较下一个字符,直到完全匹配或者遍历完了needle
字符串。
步骤如下:
- 若
needle
是空字符串,则返回下标 0。 - 计算
haystack
和needle
的长度,分别记为n
和m
。 - 从
haystack
的第一个字符开始遍历,遍历范围为n - m + 1
。 - 对于每个位置
i
,使用指针j
遍历needle
,并比较haystack[i+j]
和needle[j]
的字符是否相等。如果相等,继续比较下一个字符;如果不相等,跳出循环。 - 如果
j
遍历到了needle
的末尾,即j == m
,说明找到了第一个匹配项,返回当前指针i
的值减去needle
的长度m
。 - 如果遍历完了
haystack
还没有找到匹配项,则返回 -1,表示needle
不是haystack
的一部分。
这样,我们就可以找到字符串 needle
在字符串 haystack
中的第一个匹配项的下标。
代码分析
-
首先,检查特殊情况,如果
needle
是空字符串,则直接返回下标 0,因为空字符串是任意字符串的子串。 -
计算
haystack
和needle
的长度,分别赋值给变量n
和m
。这样做是为了避免在循环中多次访问len()
函数。 -
使用外层循环
for i in range(n - m + 1)
遍历haystack
的每个可能的起始位置。注意,外层循环的范围是n - m + 1
,因为当剩余的字符数小于needle
的长度时,自然无法匹配。 -
在内层循环
for j in range(m)
中,使用指针j
遍历needle
的每个字符,并与haystack
中对应位置的字符进行比较。如果字符相等,则继续比较下一个字符;如果字符不相等,则退出内层循环。 -
如果内层循环正常结束,即
j
遍历到了needle
的末尾,说明找到了第一个匹配项,可以返回当前指针i
的值。 -
如果外层循环结束后还没有找到匹配项,则返回 -1,表示
needle
不是haystack
的子串。
这种算法的思路是逐个比较字符,直到找到匹配项或遍历完整个 haystack
。在最坏情况下(没有匹配项或者匹配项在最后一个起始位置),需要进行大约 (n - m + 1) * m
次字符比较操作。
完整代码
class Solution(object):
def strStr(self, haystack, needle):
if not needle: # 特殊情况判断:needle为空字符串
return 0
n = len(haystack) # haystack长度
m = len(needle) # needle长度
for i in range(n - m + 1): # 遍历haystack的每个起始位置
for j in range(m): # 遍历needle的每个字符
if haystack[i+j] != needle[j]: # 当前字符不匹配,跳出内层循环
break
else:
return i # 内层循环正常结束,找到匹配项,返回当前指针i的值
return -1 # 未找到匹配项,返回-1
详细分析
class Solution(object):
def strStr(self, haystack, needle):
"""
:type haystack: str
:type needle: str
:rtype: int
"""
这段代码定义了一个名为 Solution
的类,并在类中定义了一个名为 strStr
的方法。strStr
方法接受两个参数 haystack
和 needle
,它们分别表示被搜索的字符串和待搜索的子字符串。方法的返回类型声明为 int
。
if not needle:
return 0
这段代码首先检查特殊情况,即如果 needle
是空字符串,则直接返回 0。因为空字符串是任何字符串的子串。
n = len(haystack)
m = len(needle)
这段代码使用 len()
函数获取字符串 haystack
和 needle
的长度,并将它们分别存储在变量 n
和 m
中。这样做是为了避免在后续循环中多次调用 len()
函数,从而提高效率。
for i in range(n - m + 1):
j = 0
while j < m and haystack[i+j] == needle[j]:
j += 1
if j == m:
return i
这段代码使用两个循环来实现字符串的匹配。外层循环使用 for
循环遍历 haystack
中每个可能的起始位置,范围是 n - m + 1
。因为当剩余的字符数少于 needle
的长度时,无法进行匹配。
内层循环使用 while
循环,通过比较 haystack
中的字符和 needle
中的字符来进行匹配。循环条件为 j < m and haystack[i+j] == needle[j]
,表示当指针 j
小于 needle
的长度并且当前字符匹配时,继续循环。
如果内层循环正常结束,并且指针 j
的值等于 m
,即遍历完了整个 needle
,说明找到了匹配的子串,返回当前指针 i
的值。
return -1
如果外层循环结束后仍然没有找到匹配项,则说明 needle
不是 haystack
的子串,返回 -1。
运行效果截图
调用示例
solution = Solution()
haystack = "sadbutsad"
needle = "sad"
haystack1 = "leetcode"
needle1 = "leeto"
print(solution.strStr(haystack, needle))
print(solution.strStr(haystack1, needle1))