1. 简介
2. 实现
模板:洛谷 P1886
对于长度为 n 的序列,有一个长度为 k 的窗口。窗口从左到右每次滑动一个单位,求每次滑动后窗口内的最大值和最小值。
input
8 3
1 3 -1 -3 5 3 6 7
output
min -1 -3 -3 -3 3 3
max 3 3 5 5 6 7
思路:
deque 模拟窗口。窗口滑动时,一端加入元素、另一端移出元素;队尾既需要入队也需要出队,因此使用双端队列。q.front() < i - k + 1 时,说明队头下标已经离开窗口,应将其移除。求最大值时,维护一个从队头到队尾单调递减的队列,队头始终对应当前窗口的最大值。
在样例中,处理元素 5 前,队列中各下标对应的值为 [3, -1, -3](左侧为队头,右侧为队尾)。3 已离开窗口,应移除;-1 和 -3 都小于 5,且在 5 存在时不可能成为后续窗口的最大值,也应移除。
for(int i = 1; i <= n; i++) { // 求最大值
while(!q.empty() && q.front() < i - k + 1)
q.pop_front();
while(!q.empty() && a[q.back()] < a[i])
q.pop_back();
q.push_back(i);
maxi[i] = a[q.front()];
}
for(int i = 1; i <= n; i++) { // 求最小值
while(!q.empty() && q.front() < i - k + 1)
q.pop_front();
while(!q.empty() && a[q.back()] > a[i])
q.pop_back();
q.push_back(i);
mini[i] = a[q.front()];
}
3. 变形
示例 1:洛谷 P1714——求长度不超过 m 的最大子段和。
题意:给定序列 p1、…、pn,找出一个子段 [l, r],满足 r − l + 1 ≤ m,并使 Σi = lr pi 最大。
与模板不同的是,本题要求区间和,而非直接求最值,因此需要使用前缀和。
对序列求前缀和后,得到数组 sum[]。区间 [l, r] 的和可表示为 sum[r] - sum[l-1]。
思路:
示例 2:洛谷 P2216(二维)
题意:
给定一个由 a×b 个整数组成的矩阵,找出一个 n×n 的正方形区域,使其中最大值与最小值之差最小。
input
a = 5, b = 4, n = 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
output
1
思路: