📅  最后修改于: 2023-12-03 14:58:20.143000             🧑  作者: Mango
本文主要介绍 GATE CS 2018 中的问题18,涉及到程序的数据结构和算法。
给定一个字符串 S 和一个字符集 C,找到 S 中最短的子串,其包含 C 中的所有字符。例如,如果 S = "ADOBECODEBANC" 而 C = "ABC",则要求的子串为 "BANC"。
这是一个非常经典的问题,可以使用滑动窗口算法来解决。定义左右指针 left, right 分别指向字符串 S 的起始位置,同时维护一个计数器 count 记录当前已找到的字符集 C 中包含的字符数目。
我们先向右移动指针 right,直到找到包含 C 中所有字符的子串为止。此时,我们可以记录子串的长度 len,并尝试将指针 left 向右移动,直到不能再移动为止。
在移动 left 的过程中,需要同时更新计数器 count,每当遇到一个包含在 C 中的字符时,将计数器 count 减1。当计数器 count 为 0 时,表示当前子串已包含所有字符,可以记录下当前的子串长度 len,并继续向右移动指针 right。
在移动 left 和 right 的过程中,可以不断更新最短子串的长度,并记录其起始位置 start。当 right 指向字符串 S 的末尾时,得到的子串就是最短的子串。
时间复杂度为 O(n),其中 n 是字符串 S 的长度。
以下是该算法的 Python 代码实现:
def min_window(s: str, t: str) -> str:
need, window = {}, {}
for c in t:
need[c] = need.get(c, 0) + 1
left, right, valid = 0, 0, 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]
其中,need 用于记录字符集 C 中的字符,window 用于记录当前窗口中的字符。left, right 分别记录窗口的左右边界,valid 记录已经匹配的字符数目,start 记录最短子串的起始位置,length 记录最短子串的长度。