l = 0
for r in range(n):
count[r] += 1
while (不满足):
count[l] -= 1
l += 1
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
count = {}
res = 0
n = len(s)
l = 0
for r in range(n):
c = s[r]
count[c] = count.get(c, 0) + 1
while count[c] > 1:
count[s[l]] -= 1
l += 1
res = max(res, r - l + 1)
return res
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = “ADOBECODEBANC”, t = “ABC”
输出:“BANC”
解释:最小覆盖子串 “BANC” 包含来自字符串 t 的 ‘A’、‘B’ 和 ‘C’。
class Solution:
def minWindow(self, s: str, t: str) -> str:
ans_left, ans_right = -1, len(s)
left = 0
cnt_s = Counter() # s 子串字母的出现次数
cnt_t = Counter(t) # t 中字母的出现次数
for right, c in enumerate(s): # 移动子串右端点
cnt_s[c] += 1 # 右端点字母移入子串
while cnt_s >= cnt_t: # 涵盖
if right - left < ans_right - ans_left: # 找到更短的子串
ans_left, ans_right = left, right # 记录此时的左右端点
cnt_s[s[left]] -= 1 # 左端点字母移出子串
left += 1 # 移动子串左端点
return "" if ans_left < 0 else s[ans_left: ans_right + 1]
注意counter的用法, 可直接用>=; 同时咱们对答案的更新应该在while内部
(略)
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其总和大于等于 target 的长度最小的
子数组
[numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0
class Solution:
def totalFruit(self, fruits: List[int]) -> int:
count = {}
l = 0
ans = 0
for r in range(len(fruits)):
count[fruits[r]] = count.get(fruits[r], 0) + 1
while (len(count)) > 2:
count[fruits[l]] -= 1
if count[fruits[l]] == 0:
count.pop(fruits[l])
l += 1
ans = max(ans, r - l + 1)
return ans
给定一个正整数数组 nums和一个整数 k,返回 nums 中 「好子数组」 的数目。
如果 nums 的某个子数组中不同整数的个数恰好为 k,则称 nums 的这个连续、不一定不同的子数组为 「好子数组 」。
输入:nums = [1,2,1,2,3], k = 2
输出:7
解释:恰好由 2 个不同整数组成的子数组:[1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2].
一开始我的做法还是:
class Solution:
def subarraysWithKDistinct(self, nums: List[int], k: int) -> int:
count = {}
l = 0
ans = 0
for r in range(len(nums)):
count[nums[r]] = count.get(nums[r], 0) + 1
while len(count) > k:
count[nums[l]] -= 1
if count[nums[l]] == 0:
count.pop(nums[l])
l += 1
ans += r - l + 1
return ans
其实这只解决最多k
个的情况, 不是恰好k, 那我们直接用最多k
减去最多k-1
不就可以了
class Solution:
def subarraysWithKDistinct(self, nums: List[int], k: int) -> int:
def helper(k):
ans = 0
n = len(nums)
l = 0
g = defaultdict(int)
for r, x in enumerate(nums):
g[x] += 1
while len(g) > k:
g[nums[l]] -= 1
if g[nums[l]] == 0:
del g[nums[l]]
l += 1
# 从上面循环出来一定保证g.keys() == k
ans += r - l + 1
return ans
return helper(k) - helper(k-1)
给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。
如果可以将 x 恰好 减到 0 ,返回 最小操作数 ;否则,返回 -1 。
灵神一句话, 正难则反, 直接点通任督二脉, 求
两边 = x
<=>中间=sum - x
, 则转化为求最长子数组s.t.和为sum - x
class Solution:
def minOperations(self, nums: List[int], x: int) -> int:
target = sum(nums) - x
if target < 0: return -1 # 全部移除也无法满足要求
ans = -1
left = s = 0
for right, x in enumerate(nums):
s += x
while s > target: # 缩小子数组长度
s -= nums[left]
left += 1
if s == target:
ans = max(ans, right - left + 1)
return -1 if ans < 0 else len(nums) - ans
给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k 个 0 ,则返回 数组中连续 1 的最大个数 。
输入:nums = [1,1,1,0,0,0,1,1,1,1,0], K = 2
输出:6
解释:[1,1,1,0,0,1,1,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 6。
一句话, 窗口内最多k个0
class Solution:
def longestOnes(self, nums: List[int], k: int) -> int:
# 转换为滑动窗口, 窗口内最多k个0
count = 0
l = 0
n = len(nums)
ans = 0
for r in range(len(nums)):
if nums[r] == 0:
count += 1
while count > k:
if nums[l] == 0:
count -= 1
l += 1
ans = max(ans, r - l + 1)
return ans
给你一个整数数组 nums 和一个整数 k。如果某个连续子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」。
请返回这个数组中 「优美子数组」 的数目。
输入:nums = [1,1,2,1,1], k = 3
输出:2
解释:包含 3 个奇数的子数组是 [1,1,2,1] 和 [1,2,1,1] 。
class Solution:
def numberOfSubarrays(self, nums: List[int], k: int) -> int:
def help(k):
l = 0
n = len(nums)
ans = 0
count = 0 # 计数奇数的个数,而不是使用字典
for r in range(n):
if nums[r] % 2 == 1:
count += 1
while count > k:
if nums[l] % 2 == 1:
count -= 1
l += 1
ans += r - l + 1
return ans
return help(k) - help(k-1)