面试题_滑动窗口
3. 无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
slen = len(s)
if slen == 0:
return 0
occ = set()
rt, ans = -1, 0
for i in range(0, slen):
if i != 0:
occ.remove(s[i - 1])
while rt + 1 < slen and s[rt + 1] not in occ:
occ.add(s[rt + 1])
rt += 1
ans = max(ans, rt - i + 1)
return ans
76. 最小覆盖子串
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
示例 2:
输入:s = "a", t = "a"
输出:"a"
示例 3:
输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。
提示:
1 <= s.length, t.length <= 105
s 和 t 由英文字母组成
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char, int> ori, cnt;
for (const auto& e : t) {
++ori[e];
}
int left = 0, right = -1;
int ansL = -1, ansR = -1;
int curLen = INT_MAX;
int slen = s.length(), tlen = t.length();
auto check = [&]() {
for (const auto& e : ori) {
if (cnt[e.first] < e.second) {
return false;
}
}
return true;
};
while (right < slen)
{
if (ori.count(s[++right])) {
++cnt[s[right]];
}
while (check() && left <= right)
{
if (right - left + 1 < curLen) {
curLen = right - left + 1;
ansL = left;
ansR = right;
}
if (ori.count(s[left])) {
--cnt[s[left]];
}
left++;
}
}
return ansL == -1 ? "" : s.substr(ansL, ansR - ansL + 1);
}
};
class Solution:
def minWindow(self, s: str, t: str) -> str:
ori, cnt = dict(), dict()
def check():
for key, value in ori.items():
if cnt.get(key, 0) < value:
return False
return True
slen, tlen = len(s), len(t)
if tlen == 1:
return t if t in s else ""
for c in t:
ori[c] = ori.get(c, 0) + 1
left, right = 0, -1
cur_len = float('inf')
ansL, ansR = -1, -1
while right < slen:
right += 1
if right < slen and ori.get(s[right], 0):
cnt[s[right]] = cnt.get(s[right], 0) + 1
while check() and left <= right:
if right - left + 1 < cur_len:
cur_len = right - left + 1
ansL = left
ansR = left + cur_len
if ori.get(s[left], 0):
cnt[s[left]] = cnt.get(s[left], 0) - 1
left += 1
return "" if ansL == -1 else s[ansL : ansR]
239. 滑动窗口最大值
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
示例 2:
输入:nums = [1], k = 1
输出:[1]
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
# nlen = len(nums)
# # if nlen == 1:
# # return [nums[0]]
# if nlen <= k:
# return [max(nums)]
# from collections import deque
# que = deque()
# # 每次堆顶都是当前窗口的最大值的下标
# for i in range(k):
# while que and nums[i] >= nums[que[-1]]:
# que.pop()
# que.append(i)
# ans = [nums[que[0]]]
# for i in range(k, nlen):
# while que and nums[i] >= nums[que[-1]]:
# que.pop()
# que.append(i)
# while que[0] <= i - k:
# que.popleft()
# ans.append(nums[que[0]])
# return ans
nlen = len(nums)
if nlen == 1:
return [nums[0]]
if nlen <= k:
return [max(nums)]
que = collections.deque()
for i in range(k):
while que and nums[i] >= nums[que[-1]]:
que.pop()
que.append(i)
ans = [nums[que[0]]]
for i in range(k, nlen):
while que and nums[i] >= nums[que[-1]]:
que.pop()
que.append(i)
while que[0] <= i - k:
que.popleft()
ans.append(nums[que[0]])
return ans