5 九阳神功第三式 :滑动窗口
5.1 滑动窗口介绍
出处:(https://zhuanlan.zhihu.com/p/61564531)
滑动窗口法,也叫尺取法(可能也不一定相等,大概就是这样),可以用来解决一些查找满足一定条件的连续区间的性质(长度等)的问题。由于区间连续,因此当区间发生变化时,可以通过旧有的计算结果对搜索空间进行剪枝,这样便减少了重复计算,降低了时间复杂度。往往类似于“请找到满足xx的最x的区间(子串、子数组)的xx”这类问题都可以使用该方法进行解决。
5.1.1 长度最小的子数组(#209)
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。示例:
输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
一旦知道这个位置开始的子数组不会是最优答案了,我们就可以移动左端点。我们用 2 个指针,一个指向数组开始的位置,一个指向数组最后的位置,并维护区间内的和 sum 大于等于 ss 同时数组长度最小。
5.1.2 无重复字符的最长子串(#3)
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
5.1.3 最大连续1的个数 III(#1004)
给定一个由若干 0 和 1 组成的数组 A,我们最多可以将 K 个值从 0 变成 1 。
返回仅包含 1 的最长(连续)子数组的长度。
示例 1:
输入:A = [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。
示例 2:
输入:A = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
输出:10
解释:[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 10。
5.2 代表题目:尽可能使字符串相等(#1208)
5.3 触类旁通
5.3.1 至多包含 K 个不同字符的最长子串(#340会员_困难)
/*
-
Copyright © Huawei Technologies Co., Ltd. 2012-2018. All rights reserved.
-
Description: 项目 LEET_340_LongestSubstringforKDiffChar 的源文件
-
Author: f00485759
-
Create: 2019-12-16
*/
#include <stdio.h>
#include <stdbool.h>
#include “securec.h”
#define MAX_HASH_NUM 256
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int g_hash[MAX_HASH_NUM];
void Init(void)
{
(void)memset(g_hash, 0, sizeof(g_hash));
}
void HashChar(char c)
{
g_hash[c]++;
}
void DeHashChar(char c)
{
if (g_hash[c] > 0) {
g_hash[c]–;
}
}
bool IsExtendKChar(int k)
{
int count = 0;
for (int i = 0; i < MAX_HASH_NUM; i++) {
if (g_hash[i] != 0) {
count++; // 可以通过变量来记忆,减少计算量
}
if (count >= k) {
return true;
}
}return false;
}
bool IsRepeat(char c)
{
if (g_hash[c] != 0) {
return true;
}
return false;
}
int lengthOfLongestSubstringKDistinct(const char *s, int k)
{
int start, end, maxlen;
int slen = (int)strlen(s);
Init();
start = 0;
maxlen = 0;
for (end = 0; end < slen; end++) {
if (!IsExtendKChar(k) || IsRepeat(s[end])) {
HashChar(s[end]);
continue;
}
if (start == end) {
break;
}
maxlen = MAX(maxlen, end - start);
DeHashChar(s[start]);
start++;
while (IsExtendKChar(k)) {
DeHashChar(s[start]);
start++;
}
HashChar(s[end]);
}
maxlen = MAX(maxlen, end - start);
return maxlen;
}
int main()
{
const char *s = “a”;
int k = 0;
int maxlen = lengthOfLongestSubstringKDistinct(s, k);
printf("%d\n", maxlen);
return 0;
}
5.3.2 最少交换次数来组合所有的 1(#1151会员)
5.3.3 至多包含两个不同字符的最长子串(#159会员)
5.3.4 长度为 K 的无重复字符子串(#1100会员)
#define MAX_LEN 512
int g_array[MAX_LEN];
int numKLenSubstrNoRepeats(char * s, int k){
int right = 0;
int left = 0;
int result = 0;
int count = 0;
int len;
len = strlen(s);
memset(g_array, 0, sizeof(g_array));
while (right < len) {
if (g_array[s[right]] == 0) {
count++;
}
g_array[s[right]]++;
while (right - left + 1 > k) {
g_array[s[left]]--;
if (g_array[s[left]] == 0) {
count--;
}
left++;
}
printf("%d, %d, %d\n", right, left, count);
if ((right - left + 1 == k) && (count == k)) {
result++;
}
right++;
}
return result;
}