前序:来自b站左程云,个人进行笔记整理,如有错误,感谢指出!
- 窗口中的新成员如果比队列的队头成员大,队列直接清空,加入新成员(因为新成员又新又大)
- 窗口中的新成员如果比队列的队尾大,则从队尾开始,所有比新成员小的队尾元素全部删了(因为新成员比队尾的新且大)
- 窗口中的新成员如果比队列的队尾小,那么加入到队尾,因为他比较新,有可能是后续的最大值
题目一:个人开始认为的疑难点:按照前面分析说的,保持队头为每个窗口的最大值,当窗口更新的时候怎么知道是下一个窗口的最大值,后面发现l,r指针控制,而队列仅仅维护每次的最大值即可。最大值,优先队列结构也可以处理。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int help[N],arr[N];
int h,t;
int main()
{
int n , k;
cin >> n >> k;
for(int i = 0 ; i < n ; i++)
cin >> arr[i];
h = t = 0;
//先形成k - 1 的窗口,大->小
for(int i = 0 ; i < k - 1 ; i++)
{
while(h < t && arr[help[t - 1]] <= arr[i])//h <t 代表队列不为空,结构被破坏
{
t--;
}
help[t++] = i;
}
int m = n - k + 1;//这里通过枚举发现的数与数的关系 ,得到解的个数与n k的关系
int ans[m + 1];
//当前窗口k - 1长度?
for(int l = 0 , r = k - 1; l < m ; l ++ , r++)//前面已经形成了k大小的窗口,所以下一个数的开始就是k - 1 ,开始继续判断
{
while(h < t && arr[help[t - 1]] <= arr[r]){//枚举队列的数和进入的数相比,如果大于队列中的数直接弹出
t--;
}
//不大于进入
help[t++] = r;
//结算答案
ans[l] = arr[help[h]];//546
//看此时队列是否需要向左滑动。假设543,此时5是最大值。下标0,窗口滑出5已经和接下来的窗口没关系了,所以++,
if(help[h] == l){//为什么不等于就不加加呢? 563此时h位置是下标一不等于0,是因为此时的h位置依旧有可能为下一个位置的最大值
h++;//总结就是判断此时的值能不能依旧成为下一个最大值。
}
}
for(int i = 0 ; i < m ; i++)
cout << ans[i] << " ";
return 0;
}
题目二:
思路:既然是任意两个都不大于某个数x,那么窗口内最大和最小的两个数的绝对差也小于x,一旦下一个数进入窗口,就有可能有三种情况最大的数变了,破坏原平衡,最小的数变了,破坏原平衡,或者不破坏,依旧成立。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int arr[N], max1[N], min1[N];
int hmax, tmax, hmin, tmin;
int limit, n;
void Push(int r) {
while (hmax < tmax && arr[max1[tmax - 1]] <= arr[r]) {
tmax--;
}
max1[tmax++] = r;
while (hmin < tmin && arr[min1[tmin - 1]] >= arr[r]) {
tmin--;
}
min1[tmin++] = r;
}
void Pop(int l) {
//与上面同样的逻辑有没有可能成为下一个窗口的最大值
if (hmax < tmax && max1[hmax] == l) {
hmax++;
}
if (hmin < tmin && min1[hmin] == l) {
hmin++;
}
}
bool judge(int number) {
// 新进来的数 如果能入队列,与队列内的最大(小)值进行相比
int cnt1 = hmax < tmax? max(arr[max1[hmax]], number) : number;
int cnt2 = hmin < tmin? min(arr[min1[hmin]], number) : number;
return cnt1 - cnt2 <= limit;
}
int solve()
{
hmax = tmax = hmin = tmin = 0;
int ans = 0;
for (int l = 0, r = 0; l < n; l++) {
// [l,r),r永远是没有进入窗口的、下一个数所在的位置
while (r < n && judge(arr[r])) {
Push(r++);
}
ans = max(ans, r - l);
Pop(l);
}
return ans;
}
int main() {
cin >> n >> limit;
for (int i = 0; i < n; i++)
cin >> arr[i];
int res = solve();
cout << res << endl;
return 0;
}