1. LeetCode 1456 定长子串中元音的最大数目
方法1:滑动窗口
class Solution {
public int maxVowels(String s, int k) {
int n = s.length(), count = 0, ans = 0;
for (int i = 0; i < n; i++) {
count += isVowel(s.charAt(i));
if (i >= k) {
count -= isVowel(s.charAt(i - k));
}
ans = Math.max(count, ans); // count在开始阶段单调不减
}
return ans;
}
public int isVowel(char ch) {
return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' ? 1 : 0;
}
}
class Solution:
def maxVowels(self, s: str, k: int) -> int:
count = 0; ans = 0
for i, ch in enumerate(s):
count += 1 if ch in "aeiou" else 0
if i >= k:
count -= 1 if s[i - k] in "aeiou" else 0
ans = max(ans, count) # count在开始阶段单调不减
return ans
2. LeetCode 1984 学生分数的最小差值
方法1:排序 + 滑动窗口
class Solution {
public int minimumDifference(int[] nums, int k) {
Arrays.sort(nums);
int n = nums.length, ans = 1_000_00;
for (int i = 0; i < n - k + 1; i++)
ans = Math.min(ans, nums[i + k - 1] - nums[i]);
return ans;
}
}
class Solution:
def minimumDifference(self, nums: List[int], k: int) -> int:
nums.sort(); ans = 1_000_00
for i in range(len(nums) - k + 1):
ans = min(ans, nums[i + k - 1] - nums[i])
return ans
3. LeetCode 643 子数组最大平均数I
方法1:滑动窗口 + 思维
class Solution {
public double findMaxAverage(int[] nums, int k) {
int n = nums.length, val = 0;
for (int i = 0 ; i < k; i++)
val += nums[i];
int ans = val; // 本题存在负数需要先记录开始阶段的和
for (int i = k; i < n; i++) {
val += nums[i] - nums[i - k];
ans = Math.max(ans, val);
}
return 1.0 * ans / k;
}
}
class Solution:
def findMaxAverage(self, nums: List[int], k: int) -> float:
ans = val = sum(nums[ : k]) # 本题存在负数需要先记录开始阶段的和
for i in range(k, len(nums)):
val += nums[i] - nums[i - k]
ans = max(ans, val)
return ans / k
4. LeetCode 1343 大小为K且平均值大于等于阈值的子数组数目
方法1:滑动窗口
class Solution {
public int numOfSubarrays(int[] arr, int k, int threshold) {
int n = arr.length, val = 0;
for (int i = 0; i < k; i++)
val += arr[i];
int ans = val >= k * threshold ? 1 : 0;
for (int i = k; i < n; i++) {
val += arr[i] - arr[i - k];
ans += val >= k * threshold ? 1 : 0;
}
return ans;
}
}
class Solution:
def numOfSubarrays(self, arr: List[int], k: int, threshold: int) -> int:
val = sum(arr[ : k])
ans = 1 if val >= k * threshold else 0
for i in range(k, len(arr)):
val += arr[i] - arr[i - k]
ans += 1 if val >= k * threshold else 0
return ans
5. LeetCode 2090 半径为k的子数组平均值
方法1:滑动窗口
class Solution {
public int[] getAverages(int[] nums, int k) {
int n = nums.length;
int[] ans = new int[n];
Arrays.fill(ans, -1);
if (2 * k + 1 <= n) {
long val = 0; // 防止溢出
for (int i = 0; i < 2 * k; i++)
val += nums[i];
for (int i = k; i < n - k; i++) { // 遍历中心位置
val += nums[i + k];
ans[i] = (int)(val / (2 * k + 1));
val -= nums[i - k];
}
}
return ans;
}
}
class Solution:
def getAverages(self, nums: List[int], k: int) -> List[int]:
n = len(nums); ans = [-1] * n
if 2 * k + 1 <= n:
val = sum(nums[ : 2 * k])
for i in range(k, n - k): # 遍历中心位置
val += nums[i + k]
ans[i] = val // (2 * k + 1)
val -= nums[i - k]
return ans
6. LeetCode 2379 得到K个黑块的最少涂色次数
方法1:滑动窗口 + 思维
class Solution {
public int minimumRecolors(String blocks, int k) {
int n = blocks.length(), count = 0, ans = 0;
for (int i = 0; i < n; i++) {
count += blocks.charAt(i) == 'B' ? 1 : 0;
if (i >= k)
count -= blocks.charAt(i - k) == 'B' ? 1 : 0;
ans = Math.max(ans, count);
}
return Math.max(0, k - ans);
}
}
class Solution:
def minimumRecolors(self, blocks: str, k: int) -> int:
ans = val = 0
for i, ch in enumerate(blocks):
val += 1 if ch == 'B' else 0
if i >= k:
val -= 1 if blocks[i - k] == 'B' else 0
ans = max(ans, val)
return max(0, k - ans)
7. LeetCode 1052 爱生气的书店老板
方法1:滑动窗口 + 思维
class Solution {
public int maxSatisfied(int[] customers, int[] grumpy, int minutes) {
// cnt 记录定长区间生气人数 tol 记录非生气总人数
int n = customers.length, cnt = 0, ans = 0, tol = 0;
for (int i = 0; i < n; i++) {
tol += grumpy[i] == 0 ? customers[i] : 0;
cnt += grumpy[i] == 1 ? customers[i] : 0;
if (i >= minutes)
cnt -= grumpy[i - minutes] == 1 ? customers[i - minutes] : 0;
ans = Math.max(ans, cnt);
}
return tol + ans;
}
}
class Solution:
def maxSatisfied(self, customers: List[int], grumpy: List[int], minutes: int) -> int:
n = len(customers); tol, cnt, ans = 0, 0, 0
for i in range(n):
tol += customers[i] if grumpy[i] == 0 else 0
cnt += customers[i] if grumpy[i] == 1 else 0
if i >= minutes:
cnt -= customers[i - minutes] if grumpy[i - minutes] == 1 else 0
ans = max(ans, cnt)
return tol + ans
8. LeetCode 2841 几乎唯一子数组的最大和
方法1:滑动窗口 + 哈希表
class Solution {
public long maxSum(List<Integer> nums, int m, int k) {
int n = nums.size();
long val = 0; // 防止溢出
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < k; i++) {
val += nums.get(i);
map.merge(nums.get(i), 1, Integer::sum);
}
long ans = map.size() >= m ? val : 0;
for (int i = k; i < n; i++) {
val += nums.get(i) - nums.get(i - k);
map.merge(nums.get(i), 1, Integer::sum); // 将该元素加入字典中
// merge 会返回计算后的结果
if (map.merge(nums.get(i - k), -1, Integer::sum) == 0)
map.remove(nums.get(i - k));
if (map.size() >= m)
ans = Math.max(ans, val);
}
return ans;
}
}
class Solution:
def maxSum(self, nums: List[int], m: int, k: int) -> int:
n = len(nums); val = sum(nums[ : k])
cnt = Counter(nums[ : k]) # python 计数字典
ans = val if len(cnt) >= m else 0
for i in range(k, n):
val += nums[i] - nums[i - k]
cnt[nums[i]] += 1 # 加入元素
cnt[nums[i - k]] -= 1 # 删除元素
if cnt[nums[i - k]] == 0:
del cnt[nums[i - k]]
if len(cnt) >= m:
ans = max(ans, val)
return ans
9. LeetCode 2461 长度为K子数组中的最大和
方法1:滑动窗口 + 标记数组
class Solution {
public long maximumSubarraySum(int[] nums, int k) {
int MX = 1_000_00;
int[] vis = new int[MX + 1];
// cnt 记录当前区间存在多少不同数字
int n = nums.length, cnt = 0;
long val = 0; // 防止溢出
for (int i = 0; i < k; i++) {
val += nums[i];
cnt += vis[nums[i]] == 0 ? 1 : 0;
vis[nums[i]]++;
}
long ans = cnt == k ? val : 0;
for (int i = k; i < n; i++) {
val += nums[i] - nums[i - k];
// 加入 nums[i] 产生的变化
cnt += vis[nums[i]] == 0 ? 1 : 0;
vis[nums[i]]++;
// 删除 nums[i - k] 产生的变化
vis[nums[i - k]]--;
cnt -= vis[nums[i - k]] == 0 ? 1 : 0;
if (cnt == k)
ans = Math.max(ans, val);
}
return ans;
}
}
class Solution:
def maximumSubarraySum(self, nums: List[int], k: int) -> int:
vis = [0] * (1_000_00 + 1)
cnt, val, ans = 0, 0, 0
for i in range(len(nums)):
val += nums[i] # 加入元素
cnt += 1 if vis[nums[i]] == 0 else 0
vis[nums[i]] += 1
if i >= k:
val -= nums[i - k] # 删除元素
vis[nums[i - k]] -= 1
cnt -= 1 if vis[nums[i - k]] == 0 else 0
ans = max(ans, val) if cnt == k else ans
return ans
10. LeetCode 1423 可获得的最大点数
方法1:滑动窗口 + 思维
class Solution {
public int maxScore(int[] cardPoints, int k) {
// 从 k-1 到 0 再从 n-1 到 n-k 滑动
int n = cardPoints.length, val = 0;
for (int i = n - k; i < n; i++)
val += cardPoints[i];
int ans = val;
for (int i = 0; i < k; i++) {
val += cardPoints[i] - cardPoints[n - k + i];
ans = Math.max(ans, val);
}
return ans;
}
}
class Solution:
def maxScore(self, cardPoints: List[int], k: int) -> int:
ans = val = sum(cardPoints[-k : ])
for i in range(k):
val += cardPoints[i] - cardPoints[-k + i]
ans = max(ans, val)
return ans
11. LeetCode 2134 最少交换次数来组合所有的1 II
方法1:滑动窗口 + 思维
class Solution {
public int minSwaps(int[] nums) {
int n = nums.length, cnt1 = 0;
for (int i = 0; i < n; i++)
cnt1 += nums[i]; // 定区间长度 cnt1
int ans = 0, val = 0; // val 为 1 的个数
for (int i = 0; i < n - 1 + cnt1; i++) { // 可以循环
val += nums[i % n];
if (i >= cnt1)
val -= nums[i - cnt1];
ans = Math.max(ans, val);
}
return cnt1 - ans;
}
}
class Solution:
def minSwaps(self, nums: List[int]) -> int:
n = len(nums); cnt = sum(nums) # 1 的个数
ans = val = 0
for i in range(n - 1 + cnt):
val += nums[i % n]
if i >= cnt:
val -= nums[i - cnt]
ans = max(ans, val)
return cnt - ans
12. LeetCode 567 字符串的排列
13. LeetCode 438 找到字符串中所有字母异位词
14. LeetCode 2156 查找给定哈希值的子串
15. LeetCode 2953 统计完全子字符串