一.定长滑动窗口是什么及其使用场景
定长滑动窗口算法的核心思想是使用两个指针,通常称为“左指针”和“右指针”。窗口的大小是固定的,右指针用于扩展窗口,直到达到指定大小,而左指针则在窗口移动时逐步向右滑动。这样可以高效地更新窗口内的计算结果,避免重复计算。
二.刷题 + 题解(在代码中)
给你字符串
s
和整数k
。请返回字符串
s
中长度为k
的单个子字符串中可能包含的最大元音字母数。英文中的 元音字母 为(
a
,e
,i
,o
,u
)。示例 1:
输入:s = "abciiidef", k = 3 输出:3 解释:子字符串 "iii" 包含 3 个元音字母。示例 2:
输入:s = "aeiou", k = 2 输出:2 解释:任意长度为 2 的子字符串都包含 2 个元音字母。示例 3:
输入:s = "leetcode", k = 3 输出:2 解释:"lee"、"eet" 和 "ode" 都包含 2 个元音字母。示例 4:
输入:s = "rhythms", k = 4 输出:0 解释:字符串 s 中不含任何元音字母。示例 5:
输入:s = "tryhard", k = 4 输出:1提示:
1 <= s.length <= 10^5
s
由小写英文字母组成1 <= k <= s.length
class Solution:
def maxVowels(self, s: str, k: int) -> int:
l = 0 ; r = 1 # 建立两个指针
if s[l] in "aeiou":
ans = 1
else:
ans = 0
e = float("-inf")
while r <= len(s):
if s[r] in "aeiou":
ans += 1
r += 1
if r - l > k: # 当两个指针大于k(窗口长度)那么左指针将要向右滑动
if s[l] in "aeiou":
ans -= 1
l += 1
e = max(ans,e)
if r == len(s):
break
return e
给你一个由
n
个元素组成的整数数组nums
和一个整数k
。请你找出平均数最大且 长度为
k
的连续子数组,并输出该最大平均数。任何误差小于
10-5
的答案都将被视为正确答案。示例 1:
输入:nums = [1,12,-5,-6,50,3], k = 4 输出:12.75 解释:最大平均数 (12-5-6+50)/4 = 51/4 = 12.75示例 2:
输入:nums = [5], k = 1 输出:5.00000提示:
n == nums.length
1 <= k <= n <= 10**5
-10**4 <= nums[i] <= 10**4
# 这道题主要考察的区间和,主要怎么思考呢
# 1.先算出这个从0开始的窗口和。
# 2.移动指针,当移动右指针时,这个和就要加上右指针指向的值,同时左指针移动时,这个和就要减
去左指针移动前的值。
# 3.通过以上方法动态维护窗口内的和。
# 4.求区间和也可以用前缀和来求但是时间复杂度是o(2n)的,好处是以后无需再遍历。
class Solution:
def findMaxAverage(self, nums: List[int], k: int) -> float:
average = sum(nums[0:k]) / k
sum1 = average * k
i = 0
while k < len(nums):
sum1 -= nums[i]
k += 1
i += 1
sum1 += nums[k - 1]
average = max(sum1 / (k - i), average)
return average
给你一个整数数组
arr
和两个整数k
和threshold
。请你返回长度为
k
且平均值大于等于threshold
的子数组数目。示例 1:
输入:arr = [2,2,2,2,5,5,5,8], k = 3, threshold = 4 输出:3 解释:子数组 [2,5,5],[5,5,5] 和 [5,5,8] 的平均值分别为 4,5 和 6 。其他长度为 3 的子数组的平均值都小于 4 (threshold 的值)。示例 2:
输入:arr = [11,13,17,23,29,31,7,5,2,3], k = 3, threshold = 5 输出:6 解释:前 6 个长度为 3 的子数组平均值都大于 5 。注意平均值不是整数。提示:
1 <= arr.length <= 10**5
1 <= arr[i] <= 10**4
1 <= k <= arr.length
0 <= threshold <= 10**4
class Solution:
def numOfSubarrays(self, arr: List[int], k: int, threshold: int) -> int:
ans = 0
target = k * threshold
pre = 0
n = len(arr)
for i in range(n): # 右指针为i
pre += arr[i]
if i >= k:
pre -= arr[i - k] # 左指针为i - k
if i >= k - 1 and pre >= target:
ans += 1
return ans
给你一个下标从 0 开始的数组
nums
,数组中有n
个整数,另给你一个整数k
。半径为 k 的子数组平均值 是指:
nums
中一个以下标i
为 中心 且 半径 为k
的子数组中所有元素的平均值,即下标在i - k
和i + k
范围(含i - k
和i + k
)内所有元素的平均值。如果在下标i
前或后不足k
个元素,那么 半径为 k 的子数组平均值 是-1
。构建并返回一个长度为
n
的数组avgs
,其中avgs[i]
是以下标i
为中心的子数组的 半径为 k 的子数组平均值 。
x
个元素的 平均值 是x
个元素相加之和除以x
,此时使用截断式 整数除法 ,即需要去掉结果的小数部分。
- 例如,四个元素
2
、3
、1
和5
的平均值是(2 + 3 + 1 + 5) / 4 = 11 / 4 = 2.75
,截断后得到2
。示例 1:
输入:nums = [7,4,3,9,1,8,5,2,6], k = 3 输出:[-1,-1,-1,5,4,4,-1,-1,-1] 解释: - avg[0]、avg[1] 和 avg[2] 是 -1 ,因为在这几个下标前的元素数量都不足 k 个。 - 中心为下标 3 且半径为 3 的子数组的元素总和是:7 + 4 + 3 + 9 + 1 + 8 + 5 = 37 。 使用截断式 整数除法,avg[3] = 37 / 7 = 5 。 - 中心为下标 4 的子数组,avg[4] = (4 + 3 + 9 + 1 + 8 + 5 + 2) / 7 = 4 。 - 中心为下标 5 的子数组,avg[5] = (3 + 9 + 1 + 8 + 5 + 2 + 6) / 7 = 4 。 - avg[6]、avg[7] 和 avg[8] 是 -1 ,因为在这几个下标后的元素数量都不足 k 个。示例 2:
输入:nums = [100000], k = 0 输出:[100000] 解释: - 中心为下标 0 且半径 0 的子数组的元素总和是:100000 。 avg[0] = 100000 / 1 = 100000 。示例 3:
输入:nums = [8], k = 100000 输出:[-1] 解释: - avg[0] 是 -1 ,因为在下标 0 前后的元素数量均不足 k 。提示:
n == nums.length
1 <= n <= 10**5
0 <= nums[i], k <= 10**5
# 以下使用前缀和做的,也可以用“右指针加入左指针相减(上文提到过)”来维护和
class Solution:
def getAverages(self, nums: List[int], k: int) -> List[int]:
if k == 0:
return nums
n = len(nums)
l = []
o = list(accumulate(nums))
o = [0] + o
for i in range(n):
if i - k < 0 or i + k > n - 1:
l.append(-1)
else:
l.append((o[i + k + 1] - o[i - k]) // (2 * k + 1))
return l
给你一个长度为
n
下标从 0 开始的字符串blocks
,blocks[i]
要么是'W'
要么是'B'
,表示第i
块的颜色。字符'W'
和'B'
分别表示白色和黑色。给你一个整数
k
,表示想要 连续 黑色块的数目。每一次操作中,你可以选择一个白色块将它 涂成 黑色块。
请你返回至少出现 一次 连续
k
个黑色块的 最少 操作次数。示例 1:
输入:blocks = "WBBWWBBWBW", k = 7 输出:3 解释: 一种得到 7 个连续黑色块的方法是把第 0 ,3 和 4 个块涂成黑色。 得到 blocks = "BBBBBBBWBW" 。 可以证明无法用少于 3 次操作得到 7 个连续的黑块。 所以我们返回 3 。示例 2:
输入:blocks = "WBWBBBW", k = 2 输出:0 解释: 不需要任何操作,因为已经有 2 个连续的黑块。 所以我们返回 0 。提示:
n == blocks.length
1 <= n <= 100
blocks[i]
要么是'W'
,要么是'B'
。1 <= k <= n
'''
目的:求每个窗口中B的个数。关于求窗口里的个数而不是求和,最好的统计方法肯定是字典,出去了就将键对应的值减一,进去就加一,每次操作维护B出现的最少次数
'''
class Solution:
def minimumRecolors(self, blocks: str, k: int) -> int:
dict1 = Counter(blocks[:k])
ans = float("inf")
n = len(blocks)
if n == k:
return blocks.count("W")
for i in range(k,n):
ans = min(ans,dict1["W"])
dict1[blocks[i - k]] -= 1
dict1[blocks[i]] += 1
return min(ans,dict1["W"])
你有一个炸弹需要拆除,时间紧迫!你的情报员会给你一个长度为
n
的 循环 数组code
以及一个密钥k
。为了获得正确的密码,你需要替换掉每一个数字。所有数字会 同时 被替换。
- 如果
k > 0
,将第i
个数字用 接下来k
个数字之和替换。- 如果
k < 0
,将第i
个数字用 之前k
个数字之和替换。- 如果
k == 0
,将第i
个数字用0
替换。由于
code
是循环的,code[n-1]
下一个元素是code[0]
,且code[0]
前一个元素是code[n-1]
。给你 循环 数组
code
和整数密钥k
,请你返回解密后的结果来拆除炸弹!示例 1:
输入:code = [5,7,1,4], k = 3 输出:[12,10,16,13] 解释:每个数字都被接下来 3 个数字之和替换。解密后的密码为 [7+1+4, 1+4+5, 4+5+7, 5+7+1]。注意到数组是循环连接的。示例 2:
输入:code = [1,2,3,4], k = 0 输出:[0,0,0,0] 解释:当 k 为 0 时,所有数字都被 0 替换。示例 3:
输入:code = [2,4,9,3], k = -2 输出:[12,5,6,13] 解释:解密后的密码为 [3+9, 2+3, 4+2, 9+4] 。注意到数组是循环连接的。如果 k 是负数,那么和为 之前 的数字。提示:
n == code.length
1 <= n <= 100
1 <= code[i] <= 100
-(n - 1) <= k <= n - 1
# 难点是首尾是相连,如何实现呢,很简单,将右窗口和左窗口的指针(这里设为P)每次索引时对列表长度取余即可。
class Solution:
def decrypt(self, code: List[int], k: int) -> List[int]:
n = len(code)
ans = [0] * n
if k == 0:
return ans
s = list(accumulate(code + code, initial = 0))
for i in range(n):
if k > 0:
ans[i] = s[i + k + 1] - s[i + 1]
else:
ans[i] = s[i + n] - s[i + k + n]
return ans
有一个书店老板,他的书店开了
n
分钟。每分钟都有一些顾客进入这家商店。给定一个长度为n
的整数数组customers
,其中customers[i]
是在第i
分钟开始时进入商店的顾客数量,所有这些顾客在第i
分钟结束后离开。在某些分钟内,书店老板会生气。 如果书店老板在第
i
分钟生气,那么grumpy[i] = 1
,否则grumpy[i] = 0
。当书店老板生气时,那一分钟的顾客就会不满意,若老板不生气则顾客是满意的。
书店老板知道一个秘密技巧,能抑制自己的情绪,可以让自己连续
minutes
分钟不生气,但却只能使用一次。请你返回 这一天营业下来,最多有多少客户能够感到满意 。
示例 1:
输入:customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], minutes = 3 输出:16 解释:书店老板在最后 3 分钟保持冷静。 感到满意的最大客户数量 = 1 + 1 + 1 + 1 + 7 + 5 = 16.示例 2:
输入:customers = [1], grumpy = [0], minutes = 1 输出:1提示:
n == customers.length == grumpy.length
1 <= minutes <= n <= 2 * 10**4
0 <= customers[i] <= 1000
grumpy[i] == 0 or 1
'''
目的:找在以min大小的窗口什么时候能把损失降到最低,就是维护一个在窗内生气时候的客人总数,并且维护这个最大值
'''
class Solution:
def maxSatisfied(self, customers: List[int], grumpy: List[int], k: int) -> int:
n = len(customers)
suf = [0] * (n + 1)
for i in range(n - 1, -1, -1): suf[i] = suf[i + 1] + customers[i] * (1 - grumpy[i])
pre = 0
cur = sum(customers[:k])
ans = cur + pre + suf[k]
for i in range(k, n):
pre += (1 - grumpy[i - k]) * customers[i - k]
cur += customers[i] - customers[i - k]
ans = max(ans, pre + cur + suf[i + 1])
return ans
给你一个整数数组
nums
和两个正整数m
和k
。请你返回
nums
中长度为k
的 几乎唯一 子数组的 最大和 ,如果不存在几乎唯一子数组,请你返回0
。如果
nums
的一个子数组有至少m
个互不相同的元素,我们称它是 几乎唯一 子数组。子数组指的是一个数组中一段连续 非空 的元素序列。
示例 1:
输入:nums = [2,6,7,3,1,7], m = 3, k = 4 输出:18 解释:总共有 3 个长度为 k = 4 的几乎唯一子数组。分别为 [2, 6, 7, 3] ,[6, 7, 3, 1] 和 [7, 3, 1, 7] 。这些子数组中,和最大的是 [2, 6, 7, 3] ,和为 18 。示例 2:
输入:nums = [5,9,9,2,4,5,4], m = 1, k = 3 输出:23 解释:总共有 5 个长度为 k = 3 的几乎唯一子数组。分别为 [5, 9, 9] ,[9, 9, 2] ,[9, 2, 4] ,[2, 4, 5] 和 [4, 5, 4] 。这些子数组中,和最大的是 [5, 9, 9] ,和为 23 。示例 3:
输入:nums = [1,2,1,2,1,2,1], m = 3, k = 3 输出:0 解释:输入数组中不存在长度为k = 3
的子数组含有至少m = 3
个互不相同元素的子数组。所以不存在几乎唯一子数组,最大和为 0 。提示:
1 <= nums.length <= 2 * 10**4
1 <= m <= k <= nums.length
1 <= nums[i] <= 10**9
'''
m个互不相同的元素是难点,不同,可以想到集合去重然后算出元素个数也就是长度,但是set需要n,len也需要n,时间复杂度就上来了,有个方法是统计,用字典。当值为零时将这个键删去,这都是0(1)的,然用len来算出不用的个数即可。
'''
class Solution:
def maxSum(self, nums: List[int], m: int, k: int) -> int:
ans = 0
s = sum(nums[:k - 1])
cnt = Counter(nums[:k - 1])
for out , in_ in zip(nums,nums[k - 1:]):
s += in_
cnt[in_] += 1
if len(cnt) >= m:
ans = max(ans,s)
s -= out
cnt[out] -= 1
if cnt[out] == 0:
del cnt[out]
return ans
给你一个整数数组
nums
和一个整数k
。请你从nums
中满足下述条件的全部子数组中找出最大子数组和:
- 子数组的长度是
k
,且- 子数组中的所有元素 各不相同 。
返回满足题面要求的最大子数组和。如果不存在子数组满足这些条件,返回
0
。子数组 是数组中一段连续非空的元素序列。
示例 1:
输入:nums = [1,5,4,2,9,9,9], k = 3 输出:15 解释:nums 中长度为 3 的子数组是: - [1,5,4] 满足全部条件,和为 10 。 - [5,4,2] 满足全部条件,和为 11 。 - [4,2,9] 满足全部条件,和为 15 。 - [2,9,9] 不满足全部条件,因为元素 9 出现重复。 - [9,9,9] 不满足全部条件,因为元素 9 出现重复。 因为 15 是满足全部条件的所有子数组中的最大子数组和,所以返回 15 。示例 2:
输入:nums = [4,4,4], k = 3 输出:0 解释:nums 中长度为 3 的子数组是: - [4,4,4] 不满足全部条件,因为元素 4 出现重复。 因为不存在满足全部条件的子数组,所以返回 0 。提示:
1 <= k <= nums.length <= 10**5
1 <= nums[i] <= 10**5
# 与2841题思路相似
class Solution:
def maximumSubarraySum(self, nums: List[int], k: int) -> int:
l = Counter(nums[:k - 1])
n = len(nums)
ans = 0
sum1 = sum(nums[:k - 1])
for i in range(k - 1,n):
l[nums[i]] += 1
sum1 += nums[i]
if len(l) == k:
ans = max(ans,sum1)
l[nums[i - k + 1]] -= 1
if l[nums[i - k + 1]] <= 0:
del l[nums[i - k + 1]]
sum1 -= nums[i - k + 1]
return ans
几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组
cardPoints
给出。每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿
k
张卡牌。你的点数就是你拿到手中的所有卡牌的点数之和。
给你一个整数数组
cardPoints
和整数k
,请你返回可以获得的最大点数。示例 1:
输入:cardPoints = [1,2,3,4,5,6,1], k = 3 输出:12 解释:第一次行动,不管拿哪张牌,你的点数总是 1 。但是,先拿最右边的卡牌将会最大化你的可获得点数。最优策略是拿右边的三张牌,最终点数为 1 + 6 + 5 = 12 。示例 2:
输入:cardPoints = [2,2,2], k = 2 输出:4 解释:无论你拿起哪两张卡牌,可获得的点数总是 4 。示例 3:
输入:cardPoints = [9,7,7,9,7,7,9], k = 7 输出:55 解释:你必须拿起所有卡牌,可以获得的点数为所有卡牌的点数之和。示例 4:
输入:cardPoints = [1,1000,1], k = 1 输出:1 解释:你无法拿到中间那张卡牌,所以可以获得的最大点数为 1 。示例 5:
输入:cardPoints = [1,79,80,1,1,1,200,1], k = 3 输出:202提示:
1 <= cardPoints.length <= 10^5
1 <= cardPoints[i] <= 10^4
1 <= k <= cardPoints.length
class Solution:
def maxScore(self, cardPoints: List[int], k: int) -> int:
sum1 = sum(cardPoints[:k])
ans = 0
n = len(cardPoints)
i = k - 1
j = n - 1
for o in range(k + 1):
ans = max(sum1,ans)
sum1 -= cardPoints[i]
sum1 += cardPoints[j]
i -= 1
j -= 1
return ans
给你一个字符串
s
,请你返回满足以下条件且出现次数最大的 任意 子串的出现次数:
- 子串中不同字母的数目必须小于等于
maxLetters
。- 子串的长度必须大于等于
minSize
且小于等于maxSize
。示例 1:
输入:s = "aababcaab", maxLetters = 2, minSize = 3, maxSize = 4 输出:2 解释:子串 "aab" 在原字符串中出现了 2 次。 它满足所有的要求:2 个不同的字母,长度为 3 (在 minSize 和 maxSize 范围内)。示例 2:
输入:s = "aaaa", maxLetters = 1, minSize = 3, maxSize = 3 输出:2 解释:子串 "aaa" 在原字符串中出现了 2 次,且它们有重叠部分。示例 3:
输入:s = "aabcabcab", maxLetters = 2, minSize = 2, maxSize = 3 输出:3示例 4:
输入:s = "abcde", maxLetters = 2, minSize = 3, maxSize = 3 输出:0提示:
1 <= s.length <= 10^5
1 <= maxLetters <= 26
1 <= minSize <= maxSize <= min(26, s.length)
s
只包含小写英文字母。
# 引用佬的一句话秒解"这题很明显maxSize没有用,因为长的串重复它的子串一定也重复”
class Solution:
def maxFreq(self, s: str, maxLetters: int, minSize: int, maxSize: int) -> int:
dict1 = Counter(s[:minSize-1])
dict2 = defaultdict(int)
n = len(s)
for i in range(minSize - 1,n):
dict1[s[i]] += 1
if len(dict1) <= maxLetters:
dict2[s[i - minSize + 1:i + 1]] += 1
dict1[s[i - minSize + 1]] -= 1
if dict1[s[i - minSize + 1]] == 0:
del dict1[s[i - minSize + 1]]
return max(dict2.values()) if len(dict2) >= 1 else 0
给你一个长度为
n
的整数数组nums
,请你求出每个长度为k
的子数组的 美丽值 。一个子数组的 美丽值 定义为:如果子数组中第
x
小整数 是 负数 ,那么美丽值为第x
小的数,否则美丽值为0
。请你返回一个包含
n - k + 1
个整数的数组,依次 表示数组中从第一个下标开始,每个长度为k
的子数组的 美丽值 。
子数组指的是数组中一段连续 非空 的元素序列。
示例 1:
输入:nums = [1,-1,-3,-2,3], k = 3, x = 2 输出:[-1,-2,-2] 解释:总共有 3 个 k = 3 的子数组。 第一个子数组是[1, -1, -3]
,第二小的数是负数 -1 。 第二个子数组是[-1, -3, -2]
,第二小的数是负数 -2 。 第三个子数组是[-3, -2, 3] ,第二小的数是负数 -2 。
示例 2:
输入:nums = [-1,-2,-3,-4,-5], k = 2, x = 2 输出:[-1,-2,-3,-4] 解释:总共有 4 个 k = 2 的子数组。[-1, -2] 中第二小的数是负数 -1 。
[-2, -3] 中第二小的数是负数 -2 。
[-3, -4] 中第二小的数是负数 -3 。
[-4, -5] 中第二小的数是负数 -4 。
示例 3:
输入:nums = [-3,1,2,-3,0,-3], k = 2, x = 1 输出:[-3,0,-3,-3,-3] 解释:总共有 5 个 k = 2 的子数组。[-3, 1] 中最小的数是负数 -3 。
[1, 2] 中最小的数不是负数,所以美丽值为 0 。
[2, -3] 中最小的数是负数 -3 。
[-3, 0] 中最小的数是负数 -3 。
[0, -3] 中最小的数是负数 -3 。
提示:
n == nums.length
1 <= n <= 10**5
1 <= k <= n
1 <= x <= k
-50 <= nums[i] <= 50
class Solution:
def getSubarrayBeauty(self, nums: List[int], k: int, x: int) -> List[int]:
cnt = [0] * 101
for num in nums[:k - 1]: # 先往窗口内添加 k-1 个数
cnt[num] += 1
ans = [0] * (len(nums) - k + 1)
for i, (in_, out) in enumerate(zip(nums[k - 1:], nums)):
cnt[in_] += 1 # 进入窗口(保证窗口有恰好 k 个数)
left = x
for j in range(-50, 0): # 暴力枚举负数范围 [-50,-1]
left -= cnt[j]
if left <= 0: # 找到美丽值
ans[i] = j
break
cnt[out] -= 1 # 离开窗口
return ans
作者:灵茶山艾府
链接:https://leetcode.cn/problems/sliding-subarray-beauty/solutions/2241294/hua-dong-chuang-kou-bao-li-mei-ju-by-end-9mvl/
来源:力扣(LeetCode)
交换 定义为选中一个数组中的两个 互不相同 的位置并交换二者的值。
环形 数组是一个数组,可以认为 第一个 元素和 最后一个 元素 相邻 。
给你一个 二进制环形 数组
nums
,返回在 任意位置 将数组中的所有1
聚集在一起需要的最少交换次数。示例 1:
输入:nums = [0,1,0,1,1,0,0] 输出:1 解释:这里列出一些能够将所有 1 聚集在一起的方案: [0,0,1,1,1,0,0] 交换 1 次。 [0,1,1,1,0,0,0] 交换 1 次。 [1,1,0,0,0,0,1] 交换 2 次(利用数组的环形特性)。 无法在交换 0 次的情况下将数组中的所有 1 聚集在一起。 因此,需要的最少交换次数为 1 。示例 2:
输入:nums = [0,1,1,1,0,0,1,1,0] 输出:2 解释:这里列出一些能够将所有 1 聚集在一起的方案: [1,1,1,0,0,0,0,1,1] 交换 2 次(利用数组的环形特性)。 [1,1,1,1,1,0,0,0,0] 交换 2 次。 无法在交换 0 次或 1 次的情况下将数组中的所有 1 聚集在一起。 因此,需要的最少交换次数为 2 。示例 3:
输入:nums = [1,1,0,0,1] 输出:0 解释:得益于数组的环形特性,所有的 1 已经聚集在一起。 因此,需要的最少交换次数为 0提示:
1 <= nums.length <= 10**5
nums[i]
为0
或者1
class Solution:
def minSwaps(self, nums: List[int]) -> int:
k = nums.count(1)
n = len(nums)
dict1 = Counter(nums[:k - 1])
ans = nums[:k].count(0)
for i in range(k - 1,n + k):
dict1[nums[i % n]] += 1 # 想要不不报错并且像环那样可以对数组长度取余
ans = min(ans,dict1[0])
dict1[nums[(i - k + 1) % n]] -= 1
return ans
给你两个字符串
s1
和s2
,写一个函数来判断s2
是否包含s1
的排列
。如果是,返回true
;否则,返回false
。换句话说,
s1
的排列之一是s2
的 子串 。示例 1:
输入:s1 = "ab" s2 = "eidbaooo" 输出:true 解释:s2 包含 s1 的排列之一 ("ba").示例 2:
输入:s1= "ab" s2 = "eidboaoo" 输出:false提示:
1 <= s1.length, s2.length <= 10**4
s1
和s2
仅包含小写字母
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
k = len(s1)
n = len(s2)
dict1 = Counter(s1)
dict2 = Counter(s2[:k - 1])
for i in range(k - 1,n):
dict2[s2[i]] += 1
if dict1 == dict2: # python中字典可以对应判断是否相等
return True
dict2[s2[i - k + 1]] -= 1
if dict2[s2[i - k + 1]] == 0: # 窗口内已经没这个,就删去这个键
del dict2[s2[i - k + 1]]
return False
给定两个字符串
s
和p
,找到s
中所有p
的异位词
的子串,返回这些子串的起始索引。不考虑答案输出的顺序。示例 1:
输入: s = "cbaebabacd", p = "abc" 输出: [0,6] 解释: 起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。 起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。示例 2:
输入: s = "abab", p = "ab" 输出: [0,1,2] 解释: 起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。 起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。 起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。提示:
1 <= s.length, p.length <= 3 * 10**4
s
和p
仅包含小写字母
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
s_len,p_len = len(s),len(p)
if s_len < p_len:
return []
ans = []
s_count = [0] * 26
p_count = [0] * 26
for i in range(p_len):
s_count[ord(s[i]) - 97] += 1
p_count[ord(p[i]) - 97] += 1
if s_count == p_count:
ans.append(0)
for i in range(s_len - p_len):
s_count[ord(s[i]) - 97] -= 1
s_count[ord(s[i + p_len]) - 97] += 1
if s_count == p_count:
ans.append(i + 1)
return ans
给你一个 下标从 0 开始 的整数数组
nums
,其中nums[i]
表示第i
名学生的分数。另给你一个整数k
。从数组中选出任意
k
名学生的分数,使这k
个分数间 最高分 和 最低分 的 差值 达到 最小化 。返回可能的 最小差值 。
示例 1:
输入:nums = [90], k = 1 输出:0 解释:选出 1 名学生的分数,仅有 1 种方法: - [90] 最高分和最低分之间的差值是 90 - 90 = 0 可能的最小差值是 0示例 2:
输入:nums = [9,4,1,7], k = 2 输出:2 解释:选出 2 名学生的分数,有 6 种方法: - [9,4,1,7] 最高分和最低分之间的差值是 9 - 4 = 5 - [9,4,1,7] 最高分和最低分之间的差值是 9 - 1 = 8 - [9,4,1,7] 最高分和最低分之间的差值是 9 - 7 = 2 - [9,4,1,7] 最高分和最低分之间的差值是 4 - 1 = 3 - [9,4,1,7] 最高分和最低分之间的差值是 7 - 4 = 3 - [9,4,1,7] 最高分和最低分之间的差值是 7 - 1 = 6 可能的最小差值是 2提示:
1 <= k <= nums.length <= 1000
0 <= nums[i] <= 10**5
# 注意审题
class Solution:
def minimumDifference(self, nums: List[int], k: int) -> int:
nums.sort()
e = float("inf")
i = 0
while k <= len(nums):
e = min(e, nums[k - 1] - nums[i])
i += 1
k += 1
if k == len(nums):
e = min(e, nums[k - 1] - nums[i])
print(k,i)
break
return e
感谢灵神的题单整理,以上是我做完题单之后的理解。