题目描述:
给定一个字符串 S
和一个字符串 T
,请在字符串 S
中找出包含 T
中所有字符的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:
- 如果
S
中不存这样的子串,则返回空字符串""
。 - 如果存在多个满足条件的最小子串,返回任意一个即可。
解题思路:
这个问题可以通过滑动窗口(Sliding Window)的方法来解决。滑动窗口是一种常用的双指针技巧,适用于一维数组或字符串等线性结构。
具体步骤:
-
初始化变量:
- 使用两个指针
left
和right
表示滑动窗口的左右边界,初始都指向S
的起始位置。 - 使用一个字典
need
来记录字符串T
中每个字符的需求量。 - 使用一个字典
window
来记录当前窗口中每个字符的数量。 - 使用一个变量
valid
来记录窗口中满足T
中字符需求的字符数量。
- 使用两个指针
-
扩展右边界:
- 移动
right
指针,将S[right]
加入窗口,并更新window
和valid
。
- 移动
-
收缩左边界:
- 当窗口中的字符已经满足
T
的需求时,尝试收缩窗口,移动left
指针,更新window
和valid
,并记录当前窗口的长度和起始位置。
- 当窗口中的字符已经满足
-
更新最小窗口:
- 在收缩左边界的过程中,不断更新最小窗口的长度和起始位置。
-
返回结果:
- 根据记录的最小窗口长度和起始位置,返回最小窗口子串。
代码实现:
def minWindow(s: str, t: str) -> str:
need = {}
window = {}
for char in t:
need[char] = need.get(char, 0) + 1
left, right = 0, 0
valid = 0
start, length = 0, float('inf')
while right < len(s):
# 扩展右边界
c = s[right]
right += 1
if c in need:
window[c] = window.get(c, 0) + 1
if window[c] == need[c]:
valid += 1
# 收缩左边界
while valid == len(need):
if right - left < length:
start = left
length = right - left
d = s[left]
left += 1
if d in need:
if window[d] == need[d]:
valid -= 1
window[d] -= 1
return "" if length == float('inf') else s[start:start + length]
示例
s = "ADOBECODEBANC" t = "ABC" print(minWindow(s, t)) # 输出: "BANC"
复杂度分析:
- 时间复杂度:O(N),其中 N 是字符串
S
的长度。每个字符最多被访问两次(一次被right
指针访问,一次被left
指针访问)。 - 空间复杂度:O(|T|),其中 |T| 是字符串
T
的长度。主要是用于存储need
和window
字典。
总结:
滑动窗口是一种高效解决字符串子串问题的方法,通过双指针的移动来维护一个动态的窗口,并在窗口满足条件时进行收缩,从而找到满足条件的最小子串。这个方法在很多类似的问题中都有广泛的应用。
发表回复