题目难度: 中等
今天继续更新程序员面试金典系列, 大家在公众号 算法精选 里回复 面试金典 就能看到该系列当前连载的所有文章了, 记得关注哦~
假设你有两个数组,一个长一个短,短的元素均不相同。找到长数组中包含短数组所有的元素的最短子数组,其出现顺序无关紧要。
返回最短子数组的左端点和右端点,如有多个满足条件的子数组,返回左端点最小的一个。若不存在,返回空数组。
O(B+S): 假设 B 是 big 数组的长度, S 是 small 数组的长度, 那么将 small 数组转计数字典需要 O(S)时间, 而滑动窗口部分需要 O(2*B)时间 (每个数字只会被访问两次)O(S): 额外计数字典存储 small 的值与计数的映射class Solution:
def shortestSeq(self, big: List[int], small: List[int]) -> List[int]:
# 滑动窗口+计数字典+尚未匹配个数
n = len(big)
unmatch = len(small)
mnLen = float("inf")
# 先将small数组转成计数字典{val:cnt}
cnts = collections.Counter(small)
res = []
i = 0
for j in range(n):
if big[j] in cnts:
# 只考虑在small数组中的元素
if cnts[big[j]] == 1:
# 首次遇到该元素, 尚未匹配个数减1
unmatch -= 1
# 更新计数
cnts[big[j]] -= 1
if unmatch == 0:
# 全部匹配, 左边界向右移, 直到尚未匹配个数再次大于0
while unmatch == 0:
if big[i] in cnts:
# 只考虑在small数组中的元素
if cnts[big[i]] == 0:
# 当前元素计数为0, 再向右移时会导致当前数字不再匹配, 尚未匹配个数加1
unmatch += 1
# 更新计数
cnts[big[i]] += 1
i += 1
# 当前可以匹配所有数字的最小窗口就是[i-1,j]
curLen = j - i + 2
if curLen < mnLen:
# 如果当前窗口长度更小, 则更新最终结果
# 注意这里长度相等时不更新, 因为题目要求在有多个长度相等的最小窗口时, 返回左端点最小的一个
mnLen = curLen
res = [i - 1, j]
return res
大家可以在下面这些地方找到我~😊
我的公众号: 算法精选, 欢迎大家扫码关注~😊
