滑动窗口法可以用来解决一些查找满足一定条件的连续区间的性质(长度等)问题,可以看做是一种双指针方法的特例,两个指针都起始于原点,并一前一后向终点前进。还有一种双指针方法,其两个指针一始一终,并相向靠近,这种方法的内在思想和滑动窗口非常类似
1. 爱生气的书店老板
代码实现:
滑动窗口——双指针:一前一后
int maxSatisfied(int *customers, int customersSize, int *grumpy, int grumpySize, int minutes) { int sum = 0; for (int i = 0; i < customersSize; i++) { if (grumpy[i] == 0) { sum += customers[i]; } } int increase = 0; int i = 0, j = minutes - 1; while (j < customersSize) { int num = 0; for (int k = i; k <= j; k++) { if (grumpy[k] == 1) { num += customers[k]; } } if (num > increase) { increase = num; } i++; j++; } return sum + increase; }
2. 长度最小的子数组
代码实现:
int minSubArrayLen(int target, int *nums, int numsSize) { int result = INT32_MAX; int sum = 0; // 滑动窗口数值之和 int i = 0; // 滑动窗口起始位置 int subLength = 0; // 滑动窗口的长度 for (int j = 0; j < numsSize; j++) { sum += nums[j]; // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件 while (sum >= target) { subLength = (j - i + 1); // 取子序列的长度 result = result < subLength ? result : subLength; sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置) } } // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列 return result == INT32_MAX ? 0 : result; }
3. 最小覆盖子串
代码实现:
4. 无重复字符的最长子串
代码实现:
5. 最大连续1的个数 III
代码实现:
6. 盛最多水的容器
代码实现:
方法一:暴力解法——超时
#define min(a, b) ((a) > (b) ? (b) : (a)) #define max(a, b) ((a) > (b) ? (a) : (b)) int maxArea(int *height, int heightSize) { int ans = 0; for (int i = 0; i < heightSize; i++) { for (int j = i; j < heightSize; j++) { int area = min(height[i], height[j]) * (j - i); ans = max(ans, area); } } return ans; }
方法二:双指针
#define min(a, b) ((a) > (b) ? (b) : (a)) #define max(a, b) ((a) > (b) ? (a) : (b)) int maxArea(int *height, int heightSize) { int l = 0, r = heightSize - 1; int ans = 0; while (l < r) { int area = min(height[l], height[r]) * (r - l); ans = max(ans, area); if (height[l] <= height[r]) { l++; } else { r--; } } return ans; }