滑动窗口
滑动窗口
209. 长度最小的子数组
int min(int a, int b) {
return a > b ? b : a;
}
int minSubArrayLen(int target, int *nums, int numsSize) {
int res = 0x7fffffff;
for (int l = 0, r = 0, sum = 0; r < numsSize; r++) {
// 查看以nums[r]结尾的子数组中是否有符合条件的
sum += nums[r];
// 尽量减小以nums[r]结尾的子数组长度
while (sum - nums[l] >= target) {
sum -= nums[l];
l++;
}
// 记录所有位置结尾中的最短数组
if (sum >= target) res = min(res, r - l + 1);
}
return res == 0x7fffffff ? 0 : res;
}
3. 无重复字符的最长子串
int max(int a, int b) {
return a > b ? a : b;
}
int lengthOfLongestSubstring(char *s) {
int len = strlen(s);
if (len < 2) return len;
// 记录字符是否在当前窗口中
int *hashSet = (int *) calloc(128, sizeof(int));
int left = 0, right = 0;
hashSet[s[right]] = 1;
int res = 1;
while (right + 1 < len) {
// 待进入窗口的下个字符
char nextChar = s[right + 1];
if (hashSet[nextChar] == 0) {
// 未出现过就加入到窗口中
hashSet[nextChar] = 1;
right++;
// 更新最大长度
res = max(res, right - left + 1);
} else {
// 已经出现在窗口中,就移动left,去掉left之前的字符
while (left <= right && s[left] != nextChar) {
hashSet[s[left]] = 0;
left++;
}
// 此时s[left]和nextChar相等,窗口整体右移一格,相当于从窗口中删除s[left]
left++;
right++;
}
}
return res;
}
int max(int a, int b) {
return a > b ? a : b;
}
int lengthOfLongestSubstring(char *s) {
int len = strlen(s);
int res = 0;
// 记录每个字符上次出现的位置
int last[128];
memset(last, -1, sizeof(int) * 128);
for (int l = 0, r = 0; r < len; r++) {
// 更新窗口左边界
l = max(l, last[s[r]] + 1);
// 记录最大窗口长度
res = max(res, r - l + 1);
// 更新当前字符最后一次出现的位置
last[s[r]] = r;
}
return res;
}
76. 最小覆盖子串
// 题目默认如果存在则唯一
char *minWindow(char *s, char *t) {
int lenS = strlen(s);
int lenT = strlen(t);
if (lenS < lenT) {
char *res = "";
return res;
}
// 负数表示t中字符在s中需要出现的次数,其他的表示其他字符在s中出现的次数
int map[256] = {0};
for (int i = 0; i < lenT; ++i) map[t[i]]--;
// 最小覆盖子串的长度
int len = 0x7fffffff;
// 最小覆盖子串的起始下标
int start = 0;
// 需要出现的各个字符的总个数
int count = lenT;
for (int r = 0, l = 0; r < lenS; ++r) {
// 是t中的字符,则出现总次数减一
if (map[s[r]] < 0) count--;
// 当前字符出现次数加一
map[s[r]]++;
// 窗口已经包含t中所有字符,即s中已经出现了覆盖子串
if (count == 0) {
// 大于0说明可以从窗口左边移除,从而缩小窗口大小
// 小于等于0时不能移除,否则就凑不齐t中的字符
while (map[s[l]] > 0) {
map[s[l]]--;
l++;
}
if (r - l + 1 < len) {
// 记录窗口大小
len = r - l + 1;
// 记录窗口起始位置
start = l;
}
}
}
if (len == 0x7fffffff) {
char *res = "";
return res;
} else {
char *res = (char *) malloc(sizeof(char) * (len + 1));
res[len] = '\0';
for (int i = 0; i < len; ++i) res[i] = s[start++];
return res;
}
}
134. 加油站
// O(n^2)超时
int canCompleteCircuit(int *gas, int gasSize, int *cost, int costSize) {
// 从每个位置开始尝试
for (int i = 0; i < gasSize; ++i) {
// 站点数
int count = gasSize;
// 出发点
int pos = i;
// 当前油量
int cur = 0;
while (count > 0) {
// 先加上油
cur += gas[pos];
// 油量不够到下个加油站
if (cost[pos] > cur) break;
// 消耗汽油到下个加油站
cur -= cost[pos];
pos = (pos + 1) % gasSize;
count--;
}
if (count == 0) return i;
}
return -1;
}
// O(n^2)超时
int canCompleteCircuit(int *gas, int gasSize, int *cost, int costSize) {
int arr[gasSize];
// 记录余量
for (int i = 0; i < gasSize; ++i)
arr[i] = gas[i] - cost[i];
// 从每个位置开始尝试
for (int i = 0; i < gasSize; ++i) {
// 站点数
int count = gasSize;
// 出发点
int pos = i;
// 余量前缀和
int prefix = 0;
while (count > 0) {
// 先加上油
prefix += arr[pos];
// 油量不够到下个加油站
if (prefix < 0) break;
// 消耗汽油到下个加油站
pos = (pos + 1) % gasSize;
count--;
}
if (count == 0) return i;
}
return -1;
}
// O(n^2)超时
int canCompleteCircuit(int *gas, int gasSize, int *cost, int costSize) {
// 从每个位置开始尝试
for (int i = 0; i < gasSize; ++i) {
// 站点数
int count = gasSize;
// 出发点
int pos = i;
// 余量前缀和
int prefix = 0;
while (count > 0) {
// 余量
prefix += gas[pos] - cost[pos];
// 油量不够到下个加油站
if (prefix < 0) break;
// 消耗汽油到下个加油站
pos = (pos + 1) % gasSize;
count--;
}
if (count == 0) return i;
}
return -1;
}
// O(n)
int canCompleteCircuit(int *gas, int gasSize, int *cost, int costSize) {
// 余量前缀和
int prefixSum = 0;
// 当前窗口大小
int len = 0;
// 从每个位置开始尝试
for (int left = 0, right; left < gasSize; ++left) {
while (prefixSum >= 0) {
if (len == gasSize) return left;
// 计算窗口右边界
right = (left + len) % gasSize;
// 窗口扩大,right移入窗口
len++;
prefixSum += gas[right] - cost[right];
}
// 窗口缩小,left移除窗口
len--;
prefixSum -= gas[left] - cost[left];
}
return -1;
}
1234. 替换子串得到平衡字符串
int min(int a, int b) {
return a > b ? b : a;
}
bool ok(int *counts, int len, int require) {
for (int i = 0; i < 4; ++i) {
// 窗口外的字符频率若超过require,则无法消去多出来的字符
if (counts[i] > require) return false;
// 用长度len的窗口补齐每个字符缺失的个数require - counts[i]
len -= require - counts[i];
}
// 窗口刚好用完
return len == 0;
}
int balancedString(char *s) {
int lenS = strlen(s);
// 最多调整整个数组
int res = lenS;
// 每种字符必须出现的次数
int require = lenS / 4;
// Q W E R转换成0123
int arr[lenS];
// 统计窗口外字符出现次数
int counts[4] = {0};
for (int i = 0; i < lenS; ++i) {
arr[i] = s[i] == 'Q' ? 0 : (s[i] == 'W' ? 1 : (s[i] == 'E' ? 2 : 3));
counts[arr[i]]++;
}
// 窗口[l, r)
for (int l = 0, r = 0; l < lenS; ++l) {
while (!ok(counts, r - l, require) && r < lenS) {
// 窗口右边移入,移入的字符在counts中的计数减一
counts[arr[r]]--;
r++;
}
if (ok(counts, r - l, require))
res = min(res, r - l);
// 窗口左边移出,移出的字符在counts中的计数加一
counts[arr[l]]++;
}
return res;
}
992. K 个不同整数的子数组
int counts[20001];
// 返回nums的所有子数组中,数字种类不超过k的子数组个数
int lower(int *nums, int numsSize, int k) {
memset(counts, 0, sizeof(int) * 20001);
int res = 0;
for (int l = 0, r = 0, types = 0; r < numsSize; r++) {
// 窗口右侧移入nums[r]
// 种类数加一
if (counts[nums[r]] == 0) types++;
// 词频加一
counts[nums[r]]++;
// 种类数超过了,需要从窗口左侧移除
while (types > k) {
// 词频减一
counts[nums[l]]--;
// 刚好把这个字符全部移除
if (counts[nums[l]] == 0) types--;
l++;
}
res += r - l + 1;
}
return res;
}
int subarraysWithKDistinct(int *nums, int numsSize, int k) {
return lower(nums, numsSize, k) - lower(nums, numsSize, k - 1);
}
395. 至少有 K 个重复字符的最长子串
int max(int a, int b) {
return a > b ? a : b;
}
int longestSubstring(char *s, int k) {
int len = strlen(s);
int counts[256];
int res = 0;
// 至少有require个重复字符的最长子串
for (int require = 1; require < 256; ++require) {
memset(counts, 0, sizeof(int) * 256);
// 窗口中字符种类总数
int types = 0;
// 窗口中字符出现次数大于等于k的种类总数
int satisfy = 0;
for (int l = 0, r = 0; r < len; r++) {
counts[s[r]]++;
// 新出现了一个种类
if (counts[s[r]] == 1) types++;
// 新达标了一个种类
if (counts[s[r]] == k) satisfy++;
// 字符种类超了,开始移除左边字符
while (types > require) {
if (counts[s[l]] == 1) types--;
if (counts[s[l]] == k) satisfy--;
// 窗口左侧移出字符
counts[s[l]]--;
l++;
}
// 子串以r位置结尾,且种类总数不超过require的最大长度
if (satisfy == require) res = max(res, r - l + 1);
}
}
return res;
}
热门相关:混在三国当军阀 君归矣 士子风流 名门贵妻:暴君小心点 唐朝小官人