leetcode 滑动窗口1

  • leetcode159. 至多包含两个不同字符的最长子串
    • 1. 题目
    • 2. 解答
  • leetcode1151. 最少交换次数来组合所有的1
    • 1. 题目
    • 2. 解答
  • leetcode1004. 最大连续1的个数III
    • 1. 题目
    • 2. 解答
  • leetcode209. 长度最小的子数组
    • 1. 题目
    • 2. 解答
  • leetcode1100. 长度为K的无重复字符子串
    • 1. 题目
    • 2. 解答
  • leetcode1052. 爱生气的书店老板
    • 1. 题目
    • 2. 解答
  • leetcode904. 水果成篮
    • 1. 题目
    • 2. 解答
  • leetcode359. 至少有K个重复字符的最长子串
    • 1. 题目
    • 2. 解答
  • leetcode1423. 可获得的最大点数
    • 1. 题目
    • 2. 解答

《挑战程序设计竞赛》这本书中把滑动窗口叫做「虫取法」,我觉得非常生动形象。因为滑动窗口的两个指针移动的过程和虫子爬动的过程非常像:前脚不动,把后脚移动过来;后脚不动,把前脚向前移动。
我分享一个滑动窗口的模板,能解决大多数的滑动窗口问题:

针对最大,最长的情况

def findSubArray(nums):N = len(nums) // 数组/字符串长度left, right = 0, 0 // 双指针,表示当前遍历的区间[left, right],闭区间sums = 0 // 用于统计 子数组/子区间 是否有效,根据题目可能会改成求和/计数res = 0 // 保存最大的满足题目要求的 子数组/子串 长度while right < N: // 当右边的指针没有搜索到 数组/字符串 的结尾sums += nums[right] // 增加当前右边指针的数字/字符的求和/计数while 区间[left, right]不符合题意:// 此时需要一直移动左指针,直至找到一个符合题意的区间sums -= nums[left] // 移动左指针前需要从counter中减少left位置字符的求和/计数left += 1 // 真正的移动左指针,注意不能跟上面一行代码写反// 到 while 结束时,我们找到了一个符合题意要求的 子数组/子串res = max(res, right - left + 1) // 需要更新结果right += 1 // 移动右指针,去探索新的区间return res

滑动窗口中用到了左右两个指针,它们移动的思路是:以右指针作为驱动,拖着左指针向前走。右指针每次只移动一步,而左指针在内部 while 循环中每次可能移动多步。右指针是主动前移,探索未知的新区域;左指针是被迫移动,负责寻找满足题意的区间。

模板的整体思想是:
1、定义两个指针 left 和 right 分别指向区间的开头和结尾,注意是闭区间;定义 sums 用来统计该区间内的各个字符出现次数;
2、第一重 while 循环是为了判断 right 指针的位置是否超出了数组边界;当 right 每次到了新位置,需要增加 right 指针的求和/计数;
3、第二重 while 循环是让 left 指针向右移动到 [left, right] 区间符合题意的位置;当 left 每次移动到了新位置,需要减少 left 指针的求和/计数;
4、在第二重 while 循环之后,成功找到了一个符合题意的 [left, right] 区间,题目要求最大的区间长度,因此更新 res 为 max(res, 当前区间的长度) 。
5、right 指针每次向右移动一步,开始探索新的区间。
6、模板中的 sums 需要根据题目意思具体去修改。

leetcode159. 至多包含两个不同字符的最长子串

1. 题目

给定一个字符串 s ,找出 至多 包含两个不同字符的最长子串 t ,并返回该子串的长度。

示例 1:
输入: “eceba”
输出: 3
解释: t 是 “ece”,长度为3。

示例 2:
输入: “ccaabbb”
输出: 5
解释: t 是 “aabbb”,长度为5。

2. 解答

#define NUMSIZE 26
#define MAX(a, b) (((a) > (b)) ? (a) : (b))int solution(char *s) {int len = strlen(s);int left = 0;int right = 0;int res = 0;int count = 0;int num[NUMSIZE] = { 0 };while (right < len) {num[s[right] - 'a']++;    // 计数加1if (num[s[right] - 'a'] == 1) {count++;        // 出现新字符}while (count > 2) {num[s[left] - 'a']--;    // 计数减1if (num[s[left] - 'a'] == 0) {count--;    // 字符计数减1}left++;    // 左移}res = MAX(res, right - left + 1);right++;    // 右移}return res;
}

leetcode1151. 最少交换次数来组合所有的1

1. 题目

给出一个二进制数组data,你需要通过交换位置,将数组中 任何位置 上的 1 组合到一起,并返回所有可能中所需 最少的交换次数。

示例 1:
输入:[1,0,1,0,1]
输出:1
解释:
有三种可能的方法可以把所有的 1 组合在一起:
[1,1,1,0,0],交换 1 次;
[0,1,1,1,0],交换 2 次;
[0,0,1,1,1],交换 1 次。
所以最少的交换次数为 1。

示例 2:
输入:[0,0,0,1,0]
输出:0
解释:
由于数组中只有一个 1,所以不需要交换。

示例 3:
输入:[1,0,1,0,1,0,0,1,1,0,1]
输出:3
解释:
交换 3 次,一种可行的只用 3 次交换的解决方案是 [0,0,0,0,0,1,1,1,1,1,1]。

提示:
1 <= data.length <= 10^5
0 <= data[i] <= 1

2. 解答

/*
先计算出有多少个1,假设为k个
然后用一个固定大小为k的窗口,遍历数组,记录窗口内0的最小个数即为答案
*/#define MIN(a, b) (((a) < (b)) ? (a) : (b))int getZeroNum(int *A, int left, int right) {int num = 0;for (int i = left; i < right; i++) {if (A[i] == 0) {num++;}}return num;
}int minSwaps(int *A, int Asize) {int K = 0;for (int i = 0; i < Asize; i++) {if (A[i] == 1) {K++;}}int res = K;for (int i = 0; i < Asize - K; i++) {int num = getZeroNum(A, i, i + K);res = MIN(res, num);}return res;
}

leetcode1004. 最大连续1的个数III

1. 题目

给定一个由若干 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。

2. 解答

#define MAX(a,b) (((a) > (b)) ? (a) : (b))int longestOnes(int* A, int ASize, int K) {int left = 0;int right = 0;int res = 0;int num_zero = 0;while (right < ASize) {if (A[right] == 0) {num_zero++;}while (num_zero > K) {if (A[left++] == 0) {num_zero--;}}res = MAX(res, right - left + 1);right++;}return res;
}

leetcode209. 长度最小的子数组

1. 题目

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:
输入:target = 4, nums = [1,4,4]
输出:1

示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

提示:
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105

2. 解答

#define MIN(a,b) (((a) < (b)) ? (a) : (b))int minSubArrayLen(int target, int* nums, int numsSize) {int left = 0;int right = 0;int res = numsSize;int sum = 0;while (right < numsSize) {sum += nums[right];while (sum >= target) {res = MIN(res, right - left + 1);sum -= nums[left];left++;}right++;}return left == 0 ? 0 : res;
}

leetcode1100. 长度为K的无重复字符子串

1. 题目

给你一个字符串 S,找出所有长度为 K 且不含重复字符的子串,请你返回全部满足要求的子串的 数目。

示例 1:
输入:S = “havefunonleetcode”, K = 5
输出:6
解释:
这里有 6 个满足题意的子串,分别是:
‘havef’,‘avefu’,‘vefun’,‘efuno’,‘etcod’,‘tcode’。

示例 2:
输入:S = “home”, K = 5
输出:0
解释:
注意:K 可能会大于 S 的长度。在这种情况下,就无法找到任何长度为 K 的子串。

提示:
1 <= S.length <= 10^4
S 中的所有字符均为小写英文字母
1 <= K <= 10^4

2. 解答

#define NUMSIZE 26bool isEqual(char *s, int left, int right)
{int num[NUMSIZE] = { 0 };for (int i = left; i <= right; i++) {num[s[i] - 'a']++;if (num[s[i] - 'a'] > 1) {return false;}}return true;
}int solutionn(char *s, int K)
{int count = 0;int len = strlen(s);if (len < K) {return 0;}for (int i = 0; i < len - K; i++) {if (isEqual(s, i, i + K - 1)) {count++;}}return count;
}

leetcode1052. 爱生气的书店老板

1. 题目

今天,书店老板有一家店打算试营业 customers.length 分钟。每分钟都有一些顾客(customers[i])会进入书店,所有这些顾客都会在那一分钟结束后离开。
在某些时候,书店老板会生气。 如果书店老板在第 i 分钟生气,那么 grumpy[i] = 1,否则 grumpy[i] = 0。 当书店老板生气时,那一分钟的顾客就会不满意,不生气则他们是满意的。
书店老板知道一个秘密技巧,能抑制自己的情绪,可以让自己连续 X 分钟不生气,但却只能使用一次。
请你返回这一天营业下来,最多有多少客户能够感到满意。

示例:
输入:customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], X = 3
输出:16
解释:
书店老板在最后 3 分钟保持冷静。
感到满意的最大客户数量 = 1 + 1 + 1 + 1 + 7 + 5 = 16.

提示:
1 <= X <= customers.length == grumpy.length <= 20000
0 <= customers[i] <= 1000
0 <= grumpy[i] <= 1

2. 解答

/*
算法:
1. 计算不生气的客户数
2. 针对生气的客户,计算X分钟内,流失最多的客户
3. 不生气的客户数+生气导致流失的最多客户数(X分钟内)
[1, 0, 1, 2, 1, 1, 7, 5]
[0, 1, 0, 1, 0, 1, 0, 1]
不生气客户:
[1, 0, 1, 0, 1, 0, 7, 0]
生气客户:
[0, 0, 0, 2, 0, 1, 0, 5]
*/
#include <stdio.h>int getWindowsValue(int *customers, int index, int minutes)
{int res = 0;for (int i = 0; i < minutes; i++) {res += customers[index + i];}return res;
}int maxSatisfied(int* customers, int customersSize, int* grumpy, int grumpySize, int minutes) {int res = 0;for (int i = 0; i < customersSize; i++) {if (grumpy[i] == 0) {res += customers[i];customers[i] = 0;} }int sum = 0;int temp;for (int i = 0; i < customersSize - minutes + 1; i++) {temp = getWindowsValue(customers, i, minutes);if (temp > sum) {sum = temp;}}return (res + sum);
}

leetcode904. 水果成篮

1. 题目

在一排树中,第 i 棵树产生 tree[i] 型的水果。
你可以从你选择的任何树开始,然后重复执行以下步骤:
把这棵树上的水果放进你的篮子里。如果你做不到,就停下来。
移动到当前树右侧的下一棵树。如果右边没有树,就停下来。
请注意,在选择一颗树后,你没有任何选择:你必须执行步骤 1,然后执行步骤 2,然后返回步骤 1,然后执行步骤 2,依此类推,直至停止。
你有两个篮子,每个篮子可以携带任何数量的水果,但你希望每个篮子只携带一种类型的水果。
用这个程序你能收集的水果树的最大总量是多少?

示例 1:
输入:[1,2,1]
输出:3
解释:我们可以收集 [1,2,1]。

示例 2:
输入:[0,1,2,2]
输出:3
解释:我们可以收集 [1,2,2]
如果我们从第一棵树开始,我们将只能收集到 [0, 1]。

示例 3:
输入:[1,2,3,2,2]
输出:4
解释:我们可以收集 [2,3,2,2]
如果我们从第一棵树开始,我们将只能收集到 [1, 2]。

示例 4:
输入:[3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:我们可以收集 [1,2,1,1,2]
如果我们从第一棵树或第八棵树开始,我们将只能收集到 4 棵水果树。

提示:
1 <= tree.length <= 40000
0 <= tree[i] < tree.length

2. 解答

#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define NUMSIZE 40000int totalFruit(int* tree, int treeSize) {int num[NUMSIZE] = { 0 };int left = 0;int right = 0;int res = 0;int count = 0;while (right < treeSize) {num[tree[right]]++;if (num[tree[right]] == 1) {count++;}while (count > 2) {num[tree[left]]--;if (num[tree[left]] == 0) {count--;}left++;}res = MAX(res, right - left + 1);right++;}return res;
}

leetcode359. 至少有K个重复字符的最长子串

1. 题目

给你一个字符串 s 和一个整数 k ,请你找出 s 中的最长子串, 要求该子串中的每一字符出现次数都不少于 k 。返回这一子串的长度。

示例 1:
输入:s = “aaabb”, k = 3
输出:3
解释:最长子串为 “aaa” ,其中 ‘a’ 重复了 3 次。

示例 2:
输入:s = “ababbc”, k = 2
输出:5
解释:最长子串为 “ababb” ,其中 ‘a’ 重复了 2 次, ‘b’ 重复了 3 次。

提示:
1 <= s.length <= 104
s 仅由小写英文字母组成
1 <= k <= 105

2. 解答

#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define NUMSIZE 26int longestSubstring(char * s, int k)
{int len = strlen(s);int res = 0;for (int i = 1; i <= NUMSIZE; i++) {int left = 0;int right = 0;int typeNum = 0;int sum = 0;int num[NUMSIZE] = { 0 };// typeNum 代表 [j, i] 区间所有的字符种类数量;sum 代表满足「出现次数不少于 k」的字符种类数量while (right < len) {num[s[right] - 'a']++;// 如果添加到 num 之后为 1,说明字符总数 +1if (num[s[right] - 'a'] == 1) {typeNum++;}// 如果添加到 num 之后等于 k,说明该字符从不达标变为达标,达标数量 + 1if (num[s[right] - 'a'] == k) {sum++;}right++;// 当区间所包含的字符种类数量 typeNum 超过了当前限定的数量 i,那么我们要删除掉一些字母,即「左指针」右移while ((left < right) && (typeNum > i)) {num[s[left] - 'a']--;if (num[s[left] - 'a'] == 0) {typeNum--;}if (num[s[left] - 'a'] == k - 1) {sum--;}left++;}// 当所有字符都符合要求,更新答案if (typeNum == sum) {res = MAX(res, right - left);}}}return res;
}

leetcode1423. 可获得的最大点数

1. 题目

几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 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

2. 解答

// 由于剩余卡牌是连续的,使用一个固定长度为n-k的滑动窗口对数组cardPoints进行遍历,求出滑动窗口最小值,然后用所有卡牌的点数之和减去该最小值,即得到了拿走卡牌点数之和的最大值。#define MIN(a, b) (((a) < (b)) ? (a) : (b))int maxScore(int* cardPoints, int cardPointsSize, int k) {int windowSize = cardPointsSize - k;int sum = 0;// 选前 n-k 个作为初始值for (int i = 0; i < windowSize; i++) {sum += cardPoints[i];}int res = sum;int minSum = sum;for (int i = windowSize; i < cardPointsSize; i++) {// 滑动窗口每向右移动一格,增加从右侧进入窗口的元素值,并减少从左侧离开窗口的元素值sum += cardPoints[i] - cardPoints[i - windowSize];minSum = MIN(minSum, sum);res += cardPoints[i];}return res - minSum;
}

leetcode 滑动窗口1相关推荐

  1. LeetCode 滑动窗口(Sliding Window)类问题总结

    导语 滑动窗口类问题是面试当中的高频题,问题本身其实并不复杂,但是实现起来细节思考非常的多,想着想着可能因为变量变化,指针移动等等问题,导致程序反复删来改去,有思路,但是程序写不出是这类问题最大的障碍 ...

  2. 数据结构算法——滑动窗口问题(以LeetCode滑动窗口题为例)

    1. 滑动窗口 滑动窗口算法是在给定特定窗口大小的数组或字符串上执行要求的操作,它的原理与网络传输TCP协议中的滑动窗口协议(Sliding Window Protocol)基本一致. 这种技术可以将 ...

  3. leetcode 滑动窗口小结 (三)

    目录 978. 最长湍流子数组 题目 思路分析以及代码 1052. 爱生气的书店老板 题目 思考分析与初步代码 优化思路以及优化代码 1208. 尽可能使字符串相等 题目 思考分析以及代码 978. ...

  4. leetcode 滑动窗口小结 (二)

    目录 424. 替换后的最长重复字符 思考分析1 优化 1004. 最大连续1的个数 III 友情提醒 方法1,基于当前最大频数 方法2,基于历史最大频数 424. 替换后的最长重复字符 https: ...

  5. leetcode 滑动窗口小结 (一)

    目录 小结以及代码框架 76. 最小覆盖子串 滑动窗口 代码以及注释 567. 字符串的排列 滑动窗口 438. 找到字符串中所有字母异位词 3. 无重复字符的最长子串 化简框架 reference ...

  6. leetcode 滑动窗口

    滑动窗口 文章目录 滑动窗口 模板框架 [76. 最小覆盖子串](https://leetcode-cn.com/problems/minimum-window-substring/) 思路分析 代码 ...

  7. LeetCode滑动窗口最大值

    题目要求: 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最大值. 示 ...

  8. leetcode 滑动窗口—— 209/1456

    一.209长度最小的子数组 1.题目 https://leetcode-cn.com/problems/minimum-size-subarray-sum/ 给定一个含有 n 个正整数的数组和一个正整 ...

  9. 【leetcode个人练习记录】 滑动窗口的问题

    1.从本质上来看 ,滑窗是双指针,一根指针指向左端点,一根指针指向右端点. 2.右指针移动是可以表示扩张窗口,左指针移动表示缩小窗口. 3.如果当前元素满足需求时,可以挪动右指针尝试更优解,并且更新需 ...

最新文章

  1. 拯救“没常识”的GPT-3得靠它了,交大ACM班校友提出“Voken” 无监督学习 | EMNLP 2020...
  2. ETSI MEC — 网业协同架构
  3. 公司inur php id_,PHP——个人信息管理系统
  4. 两台Oracle服务器,使用udl测试连接
  5. Response.Redirect、 Server.Transfer、Server.Execute三者区别
  6. Spring AOP之ThrowsAdvice
  7. C++文件操作:fopen / fread / fwrite
  8. 一、把握 Netty 整体架构脉络
  9. Dijkstra 最短路
  10. Recall(召回率) Precision(准确率) F-Measure E值 sensitivity(灵敏性) specificity(特异性)漏诊率 误诊率 ROC AUC
  11. Linux怎么查询全部容器时间,linuxea:如何单单修改docker容器的系统时间
  12. 计算机专业英语第2章测试,计算机专业英语答案
  13. php无限分类排序,重新研究这个问题:php无限分类的子分类如何再排序
  14. 《21天学通Java(第7版)》—— 2.10 认证练习
  15. 差分数组(简单易懂)
  16. 干货,新手小白做影视剪辑,这样做,帮你99%避免违规侵权
  17. python京东预约抢购_京东抢购脚本js教程
  18. 提前揭秘CJ八大看点
  19. python大数据书籍推荐-大数据入门书籍推荐《Python 大数据基础》
  20. M1 MacBook安装redis

热门文章

  1. Android 轻松实现百度地图定位
  2. unity3D 音频播放
  3. 使用全局阈值进行灰度图像二值化
  4. 【数据结构】二叉树的节点总个数、叶子节点个数、第K层节点个数、二叉树的深度
  5. JSP+Struct+MySql基于BBS管理系统设计与实现(源代码+论文+中英资料+开题报告+答辩PPT)
  6. md5sum 命令 – 计算文件内容的 md5 值
  7. AUM、MAU与DAU
  8. Matlab函数学习---sum函数(计算矩阵、数组和向量元素总和)
  9. 如何通过OKR工具帮助日常工作落地
  10. 2018年个人所得税Excel计算公式