📅  最后修改于: 2023-12-03 14:54:49.637000             🧑  作者: Mango
这个问题涉及到数据结构和算法,尤其是在查找/搜索中使用散列表的知识。
给定一个字符串$s$和一组字符$S$,我们需要找到$s$中所有包含$S$中所有字符的长度为$S$中字符数的子串。例如,如果$s$为"ADOBECODEBANC",$S$为"ABC",则我们需要找到的子串为"BANC"和"ADOBEC"。
我们需要通过散列表跟踪两个指针,$start$和$end$,并确保我们只匹配$S$中的字符。我们记录$S$中每个字符在散列表中的计数,并将其与子串中每个字符的计数进行比较。如果所有字符都匹配,则我们将子串添加到结果中。然后我们移动$start$指针以查找下一个可能的子串。
具体来说,我们使用两个散列表:$S_map$跟踪$S$中字符的计数,$sub_map$跟踪子串中字符的计数。
对于每个$end$位置,我们检查$S$中的字符是否存在于$S_map$中并在$sub_map$中增加其计数。如果添加字符后,$sub_map$中$S_map$中字符的计数小于或等于$S_map$中的计数,则我们已找到一个匹配的字符。因此,我们增加$found$计数器。当$found$等于$S$中的字符数时,我们找到了一个包含$S$中所有字符的子串,因此我们记录其长度,并移动$开始指针$以查找下一个可能的子串。
由于$S$的大小固定为$K$,$sub_map$和$S_map$的大小均为$O(K)$。因此,时间复杂度为$O(nk)$,其中$n$是$s$的长度。
def find_substring(s: str, S: str) -> List[str]:
S_map = Counter(S)
k, n, found = len(S), len(s), 0
substrings = []
start, end = 0, 0
sub_map = defaultdict(int)
while end < n:
# Add a character to the sub_map
sub_map[s[end]] += 1
# If the count of character in sub_map <= S_map, it is a valid match
if S_map[s[end]] > 0 and sub_map[s[end]] <= S_map[s[end]]:
found += 1
# If found all characters in S, remove characters from start to find a shorter valid string
while found == k:
if not substrings or end - start + 1 < len(substrings[-1][0]):
substrings.append((s[start:end + 1], end - start + 1))
sub_map[s[start]] -= 1
if S_map[s[start]] > 0 and sub_map[s[start]] < S_map[s[start]]:
found -= 1
start += 1
end += 1
return [s[0: length] for s, length in substrings]