首页 > 其他分享 >滑动窗口【模板题】

滑动窗口【模板题】

时间:2023-01-11 15:33:26浏览次数:32  
标签:窗口 int 最小值 hh 滑动 prep 模板

滑动窗口

给定一个大小为 \(n≤10^6\) 的数组。

有一个大小为 \(k\) 的滑动窗口,它从数组的最左边移动到最右边。

你只能在窗口中看到 \(k\) 个数字。

每次滑动窗口向右移动一个位置。

以下是一个例子:

该数组为 [1 3 -1 -3 5 3 6 7],\(k\) 为 \(3\)。

窗口位置 最小值 最大值
[1 3 -1] -3 5 3 6 7 -1 3
1 [3 -1 -3] 5 3 6 7 -3 3
1 3 [-1 -3 5] 3 6 7 -3 5
1 3 -1 [-3 5 3] 6 7 -3 5
1 3 -1 -3 [5 3 6] 7 3 6
1 3 -1 -3 5 [3 6 7] 3 7
你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。

输入格式
输入包含两行。

第一行包含两个整数 \(n\) 和 \(k\),分别代表数组长度和滑动窗口的长度。

第二行有 \(n\) 个整数,代表数组的具体数值。

同行数据之间用空格隔开。

输出格式
输出包含两个。

第一行输出,从左至右,每个位置滑动窗口中的最小值。

第二行输出,从左至右,每个位置滑动窗口中的最大值。

输入样例:
8 3
1 3 -1 -3 5 3 6 7

输出样例:
-1 -3 -3 -3 3 3
3 3 5 5 6 7

暴力

滑动窗口暴力解法 \(O(kn) 10^{12}\)

  • prep(i,1,n - k + 1)遍历数组
  • prep(j,i,i + k - 1)每次找到以a[i]开头的长度为k的窗口的最小值minn/最大值maxnn
点击查看代码
	prep(i,1,n - k + 1){
		int minn = a[i];
		prep(j,i,i + k - 1)minn = min(minn,a[j]);
		cout << minn << " ";
	}
	cout << nl;
	prep(i,1,n - k + 1){
		int maxnn = a[i];
		prep(j,i,i + k)maxnn = max(maxnn,a[j]);
		cout << maxnn << " ";
	}
}

优化

优化方向:

  1. 双指针尺取
  • 例如:1 3 -1 -3 5 3 6 7中共存在6个长度为3的窗口
    [1 3 -1],[3 -1 -3],[-1 -3 5],[-3 5 3],[5 3 6],[3 6 7]
    有些数没有必要进行多次重复遍历,可以对答案可能有贡献的数进行存储
  • 如何存储?
    可以用双指针尺取记录对答案可能有贡献的数的下标
  • 那么什么是对答案贡献的数呢?
  • 以取最小值为例
    窗口内最小值左边的数不会是后面窗口中的最小值,所以是一定对无答案贡献的,不需要进行存储

---2.0---

点击查看代码
	int hh = 1,tt = 0;
	prep(i,1,n){
		while((tt - hh + 1 >= k || a[i] <= a[hh]) && hh <= tt)hh ++;
		++ tt = i;
		if(i >= k)cout << a[hh] << " ";
	}

(WA)-1 -3 -3 -3 5 3
(AC)-1 -3 -3 -3 3 3

  • 原因分析:
    4--6
    3 5 3
    5--7
    5 3 6

  • 应该先判断窗口是否超载,如果超载a[hh]也是对答案无贡献的,但是hh下一个元素不一定是序列里最小的!!!

  • 如果超载就得重新对窗口中的数求最小值

  • 怎么办?

  • !!存储的只是对答案可能有贡献的,不一定就是后续的答案 -> 因此普通双指针尺取在这里是不奏效的!!

  • 优化每次需要存储的数为:
    [-1],[-3],[-3 5],[-3 5 3],[3 6],[3 6 7]

  • 见上,对有答案贡献的数的存储其实也是维护一个单调递增的队列

  • 鉴于其结构特性,优化形式采用双端队列
    [1] -> [1 3] -> {[1 3 -1] -> [3 -1 -3] -> [-1 -3 5] -> [-3 5 3] -> [5 3 6] -> [3 6 7]}
    [1] -> [1 3] -> {[-1] -> [-3] -> [-3 5]-> [-3 5 3] -> [3 6]-> [3 6 7]}

---3.0---

  • 遍历数组a用数组q记录所有数的下标(入队(右))
  • 然后我们通过将对答案无贡献的数出队来维护对答案有贡献的数
  • if(q中记录的下标已经超出了窗口的范围) -> 出队(左)hh++
  • while(下一个进队的数小于等于队列中左边的数) -> 出队(右)tt--
点击查看代码
//4.0
	int hh = 0,tt  = -1;
	prep(i,1,n){
		if(i - q[hh] + 1 > k && hh <= tt)hh ++;//注意是大于k而不是大于等于,因为i是本轮的i,等于k的话q[hh]还是可能对答案有贡献的
		while(a[i] <=a[q[tt]] && hh <= tt)tt --;
		q[++ tt] = i;
		if(i >= k)cout << a[q[hh]] << " ";
	}
	cout << nl;

	hh = 0, tt = -1;
	prep(i,1,n){
		if(i - q[hh] + 1 > k && hh <= tt)hh ++;
		while(a[i] >= a[q[tt]] && hh <= tt)tt --;
		q[++ tt] = i;
		if(i >= k)cout << a[q[hh]] << " ";
	}
	cout << nl;

AC代码

点击查看代码
#include<iostream>
using namespace std;

#define prep(i,a,b) for(int i = (a); i <= (b); i ++)
#define rrep(i,a,b) for(int i = (a); i >= (b); i --)

const char nl = '\n';
int n, k;

const int N = 1e6 + 10;
int a[N],q[N];

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	cin >> n >> k;
	prep(i,1,n)cin >> a[i];

	int hh = 0,tt  = -1;
	prep(i,1,n){
		if(i - q[hh] + 1 > k && hh <= tt)hh ++;//注意是大于k而不是大于等于,因为i是本轮的i,等于k的话q[hh]还是可能对答案有贡献的
		while(a[i] <=a[q[tt]] && hh <= tt)tt --;
		q[++ tt] = i;
		if(i >= k)cout << a[q[hh]] << " ";
	}

	cout << nl;

	hh = 0, tt = -1;
	prep(i,1,n){
		if(i - q[hh] + 1 > k && hh <= tt)hh ++;
		while(a[i] >= a[q[tt]] && hh <= tt)tt --;
		q[++ tt] = i;
		if(i >= k)cout << a[q[hh]] << " ";
	}
	cout << nl;
}


标签:窗口,int,最小值,hh,滑动,prep,模板
From: https://www.cnblogs.com/J-12045/p/17043803.html

相关文章

  • STM32掌机教程3,工程模板与带灯按键测试
    我们需要“脚手架”  关于代码,我想体现出这么一个过程:我是如何一步一步修改代码的。我认为,从学习的角度来考虑,直接看最终的代码没有什么意义。写代码就像工人盖房子,盖房......
  • 如何发布组件模板?
    前置准备:完成设计制作的组件模板具体步骤:提交模板(编辑器内提交后可以在本账号下进行复用)补充模板信息提交审核进行上架步骤分解:编辑器发布点击提交模板按钮选择要发布......
  • 菜鸟金融登录页面的滑动验证码,selenium写法
    #获取拖动按钮位置并拖动defslide_auth(self):try:time.sleep(random.randint(6,8))#checkhaveslideverifyelementsor......
  • 即时(just-in-time) 的TOGAF模板
    翻译文章VisualParadigm (https://www.visual-paradigm.com/features/just-in-time-togaf-templates/) 即时(just-in-time)的TOGAF模板(Template)敏捷(Agile),可定制......
  • Vue3 异步数据渲染模板,ref 获取不到真实节点
    获取异步数据,并把数据渲染到模板中,比如todolist等。ref只有在模板渲染之后才可以获取,而异步获取数据期间,模板可能没有被渲染。因此,直接在setup执行期间获取ref、甚至......
  • 窗口门狗(WWDG)
    1定义:窗口看门狗WWDG其实和独立看门狗类似似,它是一个7位递减计数器不断的往下递减计数,当减到一个固定值0X40时还不喂狗的话,产生一个MCU复位,这个值叫窗口的下限,是......
  • SpringBoot-04-thymeleaf模板
    目录前言一、什么是模板引擎?二、引入thymeleaf依赖三、thymeleaf语法1.基础功能:传值取值2.转义字符串为标签3.for-each遍历功能前言参考自:https://www.cnblogs.com/hell......
  • 网页 frame 与多窗口处理
    知识点iframe解析添加描述如图可以看到iframe的标签iframe的多种切换方式HTML代码示例<iframesrc="1.html"id="hogwarts_id"name="hogwarts_name"></iframe>那么通过传......
  • spy++ 查看窗口 右键属不能突出显示的窗口说说明
    如图1:此时有highlight这个选项如图2:没有highlight这个选项总结:如果窗口只是显示在系统托盘,没有自己的UI界面,我能只能通过点击系统托盘右键来进行操作,那么就不......
  • win32 设置窗口的透明度
    LONGwAttr=GetWindowLong(hWnd,GWL_EXSTYLE);//设置windowsstyle这样才能进行下面的SetLayeredWindowAttributesSetWindowLong(hWnd,GWL_EXSTYLE,wAttr|WS_EX_L......