问题概述
给定两个字符串 needle 和 haystack,返回 needle 在 haystack 中第一次出现的下标,如果 needle 不是 haystack 的一部分则返回 -1。
解法 1:暴力匹配带切片(推荐)
工作原理
通过比较子字符串检查 haystack 中每个可能的起始位置:
python
class Solution:
def strStr(self, haystack, needle):
if not needle:
return 0
n = len(haystack)
m = len(needle)
for i in range(n - m + 1):
if haystack[i:i+m] == needle:
return i
return -1
复杂度分析
- 时间复杂度: O(n * m) - 其中 n 是 haystack 的长度,m 是 needle 的长度
- 空间复杂度: O(1) - 只使用常数额外空间
何时使用
- 推荐 - 简单直观
- 易于理解和实现
- 对于典型的 LeetCode 测试用例很快
解法 2:暴力匹配字符比较
工作原理
相同的方法,但逐个字符比较而不是使用切片:
python
class Solution:
def strStr(self, haystack, needle):
if not needle:
return 0
n = len(haystack)
m = len(needle)
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
return -1
复杂度分析
- 时间复杂度: O(n * m) - 其中 n 是 haystack 的长度,m 是 needle 的长度
- 空间复杂度: O(1) - 只使用常数额外空间
何时使用
- 对较长字符串更高效(避免创建子字符串)
- 可以在发现不匹配时提前终止
- 适用于 needle 很少出现的情况
对比
| 方法 | 时间 | 空间 | 最佳适用 |
|---|---|---|---|
| 暴力匹配切片 | O(n*m) | O(1) | 大多数情况,最简单代码 |
| 暴力匹配字符 | O(n*m) | O(1) | 较长字符串,稀有 needle |
总结
带切片的暴力匹配方法最简单,在大多数情况下推荐使用。逐字符比较版本对较长字符串可能更高效,因为它避免创建子字符串对象,并可以在不匹配时提前终止。两者都具有 O(n*m) 时间复杂度,对于此问题的约束是可以接受的。