神机百炼1.15-双指针/滑动窗口
滑动窗口
- 食用指南:
- 题目描述:
- 题目分析:
- 算法原理:
- 含义:
- 作用:
- 已经见过的双指针:
- 1. 单串双指针-快速排序:
- 2. 双串双指针-归并排序:
- 3. 双串双指针-逆序对个数:
- 滑动窗口模型:
- 写作步骤:
- 两步:
- 构造滑动窗口:
- 判断问题出现:
- 代码模板:
- 代码误区:
- 1. 易漏点-连锁影响:
- 2. 手动构建的Hash存储范围:
- 本篇感想:
食用指南:
对该算法程序编写以及踩坑点很熟悉的同学可以直接跳转到代码模板查看完整代码
只有基础算法的题目会有关于该算法的原理,实现步骤,代码注意点,代码模板,代码误区的讲解
非基础算法的题目只有题目分析,代码实现,代码误区
题目描述:
给定一个长度为 n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。
输入格式
第一行包含整数 n。第二行包含 n 个整数(均在 0∼105 范围内),表示整数序列。
输出格式
共一行,包含一个整数,表示最长的不包含重复的数的连续区间的长度。数据范围
1≤n≤105
输入样例:
5
1 2 2 3 5
输出样例:
3题目来源:https://www.acwing.com/problem/content/801/
题目分析:
要求:最长&连续&不重复,非常常见的要求,没有接触过的同学应该记下他们的含义:
最长:我们需要用一个临时变量去记录原本最长序列的长度,再与当前序列长度相比,决定是否要替换连续:中间某一点不满足条件,则需要舍弃这一点与之前的所有序列,下一点又从“头”做起如:12235中,第一个2不满足不重复,删掉第一个2时,1也不可取,从第二个2重新开始时最大长度从1记录不重复:需要记录一个数是否已经出现过记录一个数出现次数可以开一个标记数组,相当于实现一个简易Hash
每个整数都在0-105的范围内,刚好开一个arr[110]数组即可完成每个数出现次数的记录
对于区间问题,双指针算法是经常采用的算法
今后遇到字符串问题,序列问题,都需要考虑“使用双指针试试”
下面我们来介绍双指针算法
算法原理:
含义:
- 双指针:就是两个临时变量,一个i,一个j。
之所以叫指针,是因为我们经常使用这两个变量来记录数组或字符串下标
作用:
- 双指针的作用很多,具体问题具体分析,但是其实做几道双指针的题目你基本就见全了所有使用情况
已经见过的双指针:
1. 单串双指针-快速排序:
- 确定一个基准数x之后,我们使用双指针完成将子序列中大于x的数放在右边,小于x的数放在左边
- 此处的双指针 i j 用于在x的左右两侧进行比较和交换
void q_sort(int l, int r){if(l >= r) return;int x = l+r>>1;int i = l-1, j = r+1;while(i < l){while(arr[++i] < x);while(arr[++j] > x);if(i < j) swap(arr[i], arr[j]);} q_sort(l, j);q_sort(j+1, r);
}
有点遗忘快排的同学看这里:传送门
2. 双串双指针-归并排序:
- 有序合并两个子序列到更大的序列中时,我们用i指针遍历左子序列,j指针遍历右子序列,让所合成的大序列变得有序
- 当将辅助记录数组tmp中的元素复制到原数组arr中时,我们用i指针从l到r遍历arr数组,用j指针从0遍历tmp数组,由于复制中的数组长度相同,所以终止条件只有i<=r
const int N = 100010;
int tmp[N];
void merge_sort(int l, int r){if (l >= r) return;int mid = (l + r)>>1;merge_sort(l ,mid);merge_sort(mid+1, r);int i = l, j = mid+1, k = 0;// 此处的双指针i j用于比较两个不同的子序列while(i <= mid && j <= r){if (arr[i] < arr[j]) tmp[k++] = arr[i++];else tmp[k++] = arr[j++];}while(i <= mid) tmp[k++] = arr[i++];while(j <= r) tmp[k++] = arr[j++];//此处的双指针i j用于复制粘贴for(int i=l, j=0; i<=r; i++,j++)arr[i] = tmp[j];
}
- 忘记归并排序的同学看这里:传送门
3. 双串双指针-逆序对个数:
- 逆序对个数基于归并排序,而且对双指针的利用达到了极致,属于双指针的启发应用
- i指针所遍历的子序列本身在j指针遍历的子序列左边,
若此时arr[i] > arr[j],则构成一对逆序对
又由于左右子序列都有序,所以arr[i]及其右边有mid-i+1个元素都与arr[j]构成逆序对
const int N = 100010;
int tmp[N];
int merge_sort(int l, int r){if (l >= r) return;int mid = (l + r)>>1;int res = 0;res += merge_sort(l ,mid);res += merge_sort(mid+1, r);int i = l, j = mid+1, k = 0;// 此处的双指针i j用于比较两个不同的子序列while(i <= mid && j <= r){if (arr[i] <= arr[j]) tmp[k++] = arr[i++];else{tmp[k++] = arr[j++];res += mid-i+1;}}while(i <= mid) tmp[k++] = arr[i++];while(j <= r) tmp[k++] = arr[j++];//此处的双指针i j用于复制粘贴for(int i=l, j=0; i<=r; i++,j++)arr[i] = tmp[j];return res;
}
- 忘记归并统计逆序对个数的同学看这里:传送门
滑动窗口模型:
本题属于双指针中的滑动窗口问题,是双指针的典型应用
滑动窗口:一个快指针j负责遍历,慢指针i负责处理快指针遗留的问题
快指针j的向后移动是由于循环++
慢指针i的向后移动是由于i-j之间出现问题,为了消除问题,i指针++举例:
初始i == j == 0,直到j指针移动到第二个8前,i-j之间没有重复元素,i一直没有移动,最大长度为4当j指针移动到第二个8时,i-j之间出现重复元素8,i指针通过++右移的方式来消除一个重复元素,此时i移动到第二个8,和j位置相同,目前长度为1<4
最终j移动到了数组结尾,期间i-j一直没有出现问题,此时i保持在第二个8不动,目前长度为3<4滑动窗口的核心就在于两句话:
快指针负责遍历序列制造问题,慢指针负责解决问题。
快指针j++是由于遍历迫使,慢指针i++是由于消除问题
写作步骤:
两步:
构造滑动窗口:
int i = 0, j = 0;
int res = 0;
for(j=0; j<n; j++){while(check()){i++;}res = max (res, j-i+1);
}
判断问题出现:
- 也就是check()函数的构造,此处是一个book[]数组
代码模板:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int arr[N];
int Hash[N];
int main(){int n = 0;cin >>n;for(int i=0; i<n; i++) cin >>arr[i];int i = 0, j = 0;int maxx = 0;for(j = 0; j<n; j++){Hash[arr[j]]++;while(Hash[arr[j]]>1){Hash[arr[i]]--;i++;}maxx = max(maxx, j-i+1);}cout <<maxx;
}
代码误区:
1. 易漏点-连锁影响:
- i++的连锁影响:Hash[arr[i]]–;
- j++的连锁影响:Hash[arr[j]]++;
2. 手动构建的Hash存储范围:
- 题目明确告知所有数据在0 - 105,一方面非负,另一方面上限小,所以可以开数组存储
- 当数据存在负数或者范围非常大的时候,可以使用STL内置的map,但是有可能会被有些出题人卡STL内置的表长
- 后续的神机百炼中我会教大家飞速搭建自己的哈希表,肯定不会被卡,且时间复杂度还是O(1)
本篇感想:
- 由于本篇是双指针第一篇,所以虽然题目是滑动窗口,但是介绍了很多双指针hh(狗头)
- 看完本篇博客,恭喜已登《练气境-初期》
距离登仙境不远了,加油
神机百炼1.15-双指针/滑动窗口相关推荐
- 点赞!掌握了实在智能IPA就等于学会了神机百炼........
动漫<一人之下>正在腾讯视频热播,作为八绝技之一的神机百炼一出场便惊艳了所有人,做到了真正地以一当百. 实在智能秋季新品发布会于10月18日20时圆满举行,作为一家行业领先的人工智能科技公 ...
- 实在智能发布会带你见证什么是真正属于你的神机百炼?
动漫<一人之下>正在腾讯视频热播,作为八绝技之一的神机百炼一出场便惊艳了所有人,做到了真正地以一当百. 实在智能秋季新品发布会于10月18日20时圆满举行,作为一家行业领先的人工智能科技公 ...
- 神机百炼1.20-区间合并
区间合并 食用指南: 题目描述: 题目分析: 算法原理: 1. 区间合并: 2. vector的sort(): 存储形式: 代码实现: 代码误区: 1. 区间合并最难的地方是什么? 2. 区间合并易漏 ...
- 神机百炼3.52-Prim
Prim 食用指南: 题目描述: 题目分析: 算法原理: 模板算法: Prim算法: 1. 适用情况: 2. 存储形式: 3. 初始化: 4. 三大步骤: 5. 模拟过程: 写作步骤: 1. 外层大循 ...
- 神机百炼2.50-负环SPFA
负环SPFA 食用指南: 题目描述: 题目分析: 算法原理: 模板算法: 负环SPFA: 1. 负环可能存在哪里? 2. 存储形式: 3. 负环检测原理: 写作步骤: 1. 初始化: 2. 出队&am ...
- Leetcode双指针滑动窗口相关题目
滑动窗口 滑动窗口解决哪种问题? 滑动窗口解决给定两个字符串S和T,问你S中是否存在一个子串,包含T中的所有字符并且不含有其他字符. 窗口右指针向右移动,窗口增大,直到满足条件,这时候找到可行解. 窗 ...
- 11. Leetcode 713. 乘积小于K的子数组 (数组-同向双指针-滑动窗口)
给定一个正整数数组 nums和整数 k .请找出该数组内乘积小于 k 的连续的子数组的个数.示例 1:输入: nums = [10,5,2,6], k = 100 输出: 8 解释: 8个乘积小于10 ...
- 【小f的刷题笔记】(JS)双指针 - 滑动窗口 四类典型问题(附JS模版和详细注释代码)LeetCode76 LeetCode567 LeetCode438 LeetCode3
[滑动窗口] JS模版 利用map对象建立滑动窗口,相关题目都可以通过套框架来解决 ✔ LeetCode76 最小覆盖子串 ✔ LeetCode567 字符串的排列 ✔ LeetCode438 找到字 ...
- 10. Leetcode 209. 长度最小的子数组 (数组-同向双指针-滑动窗口)
给定一个含有 n 个正整数的数组和一个正整数 target .找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr ...
最新文章
- Google API 设计指南-设计模式
- 监视mysql 哪些指标_MySQL 监控指标
- why my own list cannot automatically scroll to load oData
- 阿里云吕漫漪:深度解析国内首个云原生数据库POLARDB的“王者荣耀”
- 在线GIF图片帧拆分工具
- 终端 ssh 上传文件_记一次将文件添加到github
- tcl如何获取键盘输入
- 双向LSTM与单向LSTM效果对比
- 数据集:各地区化妆品销量、人口数量和人均收入
- 50道经典计算机网络面试题梳理
- 【OpenDDS开发指南V3.20】第一章:介绍
- android checkboxpreference属性,如何更改android中CheckBoxPreference标题的文本颜色?
- 简易天线增益测量系统
- sql server (sqlexpress) 服务因 3417 (0xd59) 服务性错误而停止(转自太原市李江软件开发工作室)...
- 如何将webp格式转换成png?
- JVM笔记-性能监控与分析工具
- 交换机和路由器的关系
- android系统关机广播,android关机方法汇总
- Atcoder CADDi 2018 Solution
- 来自一位十余年工作经验的老电子工程师的心里话:该出手时便出手!