滑动窗口(Sliding Window)问题经常使用快慢指针(slow, fast pointer)
[0, slow) 的区域为滑动窗口已经探索过的区域
[slow, fast]的区域为滑动窗口正在探索的区域
(fast, end of array)为待探索的区域

Sliding Window的问题主要分为:
fixed size sliding windowdynamic size sliding window

fixed size sliding window: 当快指针增加的时候慢指针必须增加
non-fixed size sliding window: 快指针增加,慢指针不一定变化

使用滑动窗口可以线性时间解决问题而且可以减少空间消耗

Fixed Length Sliding Window:
1.Strstr:
Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
Input: haystack = "hello", needle = "ll"
Output: 2
要求找到短字符串在的起始位置在长字符串中的位置
所以只需要保持一个fixed sliding window的长度为短字符串的长度然后扫长字符串来寻找起始位置

   class Solution{
public int strStr(String long, String short) {
//sanity check
if(long == null || short == null) return -1;
int i = 0;
int j = needle.length();
while(i <= haystack.length() - needle.length() && j <= haystack.length()) {
if(haystack.substring(i, j).equals(needle)) {
return i;
}
i++;
j++;
}
return -1;
}
}

2.Repeated DNA Sequennce
All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACGAATTCCG". When studying DNA, it is sometimes useful to identify repeated sequences within the DNA.
Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule.
Given s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT",
Return:
["AAAAACCCCC", "CCCCCAAAAA"]
这道题给一个碱基序列,要求我们返回在given的碱基序列中重复的碱基序列
所以这道题我们可以用一个定长的滑动窗口,每次去match在given的碱基序列中任意的position从而返回所用出现过的重复的碱基序列,可以用一个HashSet的数据结构来判断是否已经检查过已经出现的序列

class Solution{
public List<String> repeatedDNASequence(String s) {
HashSet<String> window = new HashSet<String>();
HashSet<String> repeated = new HashSet<String>(); for(int i = 0; i < s.length() - 9; i++) {
if(!window.add(s.substring(i, i + 10))) {
repeated.add(s.substring(i, i + 10));
}
}
return new ArrayList<String>(repeated);
}
}

Non-fixed Size Sliding-Window
3.find all anagrams of shortString in longString
Given a string s and a non-empty string p, find all the start indices of p's anagrams in s.Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.The order of output does not matter.
Example 1:
Input:s: "cbaebabacd" p: "abc"
Output:[0, 6]
Explanation:
The substring with start index = 0 is "cba", which is an anagram of "abc".
The substring with start index = 6 is "bac", which is an anagram of "abc".
Example 2:
Input: s: "abab" p: "ab"
Output: [0, 1, 2]
Explanation:
The substring with start index = 0 is "ab", which is an anagram of "ab".
The substring with start index = 1 is "ba", which is an anagram of "ab".
The substring with start index = 2 is "ab", which is an anagram of "ab".
这道题是寻找input长字符串中所有出现子串的起始字母在长字符串中的位置
因为我们需要找到长字符串中所有match子串的字符串并且返回需要match的字串中第一个字母在长字符串中的位置,所以需要用一个动态的滑动窗口慢指针在match的子字符串的第一个字母在长字符串中的位置,快指针在最后一个match的字母在长字符串中的位置, 然后需要一个hashmap来记录每个字母出现的频率,利用length来teminate

class Solution{
public List<Integer> findAnagrams(String s, String p) {
//sanity check
List<Integer> res = new ArrayList<Integer>();
//count the frequency of each appeared character
Map<Character, Integer> map = new HashMap<Character, Integer>();
for(char c : p.toCharArray()) {
map.put(c, map.getOrDefault(0, c) + 1);
}
int fast = 0;
int slow = 0;
int count = map.size();//记录所有出现过字符的频率
//update fast pointer
while(fast < s.length()) {
char c = s.charAt(fast);
if(map.containsKey(s.charAt(fast)) {
map.put(c, map.get(fast) - 1);
if(map.get(c) == 0) count--;
}
fast++;
//update slow pointer
while(count == 0) {
char temp = s.charAt(slow);
if(map.containsKey(temp)) {
map.put(temp, map.get(temp) + 1));
if(map.get(temp) > 0) count++;
}
//store res;
if(fast - slow == p.length()) {
res.add(slow);
}
slow++;
}
}
return res;
}
}

4.Maximum Value of size K subarray
Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.
这题要求找到given数组中任意定长的滑动窗口中数的最大值,因此需要考虑一个数据结构可以在移动的滑动窗口中找到最大值,因此有几种想法:
1.在定长的滑动窗口里维持一个最大堆,因此我们可以用constant时间去找到最大值,但是考虑到每次heapify的时间需要O(logn),所以找到k个最大值需要花费O(klogn)的时间
2.还是同样在定长的滑动窗口里维持一个treeset,但是考虑到每次在treeset中添加或者删除元素需要花费O(logn)的时间,所以是否存在一个数据结构可以在线性时间内得到定长滑动窗口里的最大值?
3.因而,想到了双端队列(Deque),可以维持一个递增的双端队列
EX:[|1, 4|, 5, 3, 9], k = 3
我们先将k-1个元素放入队列:|2|
然后从第k个元素开始,一次加入新元素并删除旧元素,并且保持滑动窗口的size不变
[|1, 4, 5|, 3, 9], Deque: 5, Output: [5];
[1, |4, 5, 3|, 9], Deque: 5, 5, Output: [5, 5];
[1, 4, |5, 3, 9|], Deque: 8, Output: [5, 5, 8];
因为对于每个数组中的元素只扫描一次,所以总体时间在deque操作中也近似于线性,所以总运行时间:O(n)(amortized), 空间复杂度:O(1)

class slidingWindowMax{
public void inQueue(Deque<Integer> deque, int k) {
while(!deque.isEmpty() && deque.peekLast() < k) {
deque.pollLast();
}
deque.offerLast(num);
}
public void outQueue(Deque<Integer> deque, int k) {
if(deque.peekFirst() == k) {
deque.pollFirst();
}
}
public int[] maxSlidingWindow(int[] nums, int k) {
List<Integer> ans = new ArrayList<Integer>();
Deque<Integer> deque = new ArrayDeque<Integer>(); if(nums == null || nums.length == 0) {
return new int[]{};
} for(int i = 0; i < k - 1; i++) {
inQueue(deque, nums[i]);
} for(int i = k - 1; i < nums.length; i++) {
inQueue(deque, nums[i]);
res.add(deque.peekFirst());
outQueue(deque, nums[i - k + 1]);//delete old element
}
int[] res = new int[ans.size()];
int h = 0;
for(int num : res) {
res[h++] = num;
}
return res;
}
}

一维滑动窗口(SlidingWindow)的更多相关文章

  1. UNIX网络编程——TCP连接的建立和断开、滑动窗口

    一.TCP段格式: TCP的段格式如下图所示: 源端口号与目的端口号:源端口号和目的端口号,加上IP首部的源IP地址和目的IP地址唯一确定一个TCP连接. 序号:序号表示在这个报文段中的第一个数据字节 ...

  2. 滑动窗口计数java实现

    滑动窗口计数有很多使用场景,比如说限流防止系统雪崩.相比计数实现,滑动窗口实现会更加平滑,能自动消除毛刺. 概念上可以参考TCP的滑窗算法,可以看一下这篇文章(http://go12345.iteye ...

  3. bzoj 2093 [Poi2010]Frog——滑动窗口

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2093 找第k近的可以用一个含k个元素的滑动窗口来实现. 卡空间也还行,但卡时间.不要预处理倍 ...

  4. 滑动窗口(Sliding Window)技巧总结

    什么是滑动窗口(Sliding Window) The Sliding Problem contains a sliding window which is a sub – list that run ...

  5. LC算法技巧总结(二):双指针和滑动窗口技巧

    我把双指针技巧再分为两类,一类是「快慢指针」,一类是「左右指针」.前者解决主要解决链表中的问题,比如典型的判定链表中是否包含环:后者主要解决数组(或者字符串)中的问题,比如二分查找. 一.快慢指针的常 ...

  6. 双指针之滑动窗口(长度最小的子数组 和 和为s的连续正数序列)

    双指针之滑动窗口 (长度最小的子数组:和为s的连续正数序列) 1, 什么时候使用? (与子数组/字符串 有关的题目)~如果给了某个具体值的target,即用滑动窗口 不然就双指针(一般做法,左边< ...

  7. 7、滑动窗口套路算法框架——Go语言版

    前情提示:Go语言学习者.本文参考https://labuladong.gitee.io/algo,代码自己参考抒写,若有不妥之处,感谢指正 关于golang算法文章,为了便于下载和整理,都已开源放在 ...

  8. [LeetCode] Sliding Window Maximum 滑动窗口最大值

    Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...

  9. TCP/IP 协议中的滑动窗口

    一个例子明白发送缓冲区.接受缓冲区.滑动窗口协议之间的关系. 在上面的几篇文章中简单介绍了上述几个概念在TCP网络编程中的关系,也对应了几个基本socket系统调用的几个行为,这里再列举一个例子,由于 ...

随机推荐

  1. wireshark抓包实战(一),抓包原理

    一.什么样的"包"能被wireshark抓住呢? 1.本机 即直接抓取进出本机网卡的流量包.这种情况下,wireshark会绑定本机的一块网卡. 2.集线器 用于抓取流量泛洪,冲突 ...

  2. .NET Core 3 WPF MVVM框架 Prism系列之导航系统

    本文将介绍如何在.NET Core3环境下使用MVVM框架Prism基于区域Region的导航系统 在讲解Prism导航系统之前,我们先来看看一个例子,我在之前的demo项目创建一个登录界面: 我们看 ...

  3. 一个lock锁就可以分出低中高水平的程序员对问题的处置方式

    说到lock锁,我相信在座的各位没有不会用的,而且还知道怎么用不会出错,但让他们聊一聊为什么可以锁住,都说人以群分,大概就有了下面低中高水平的三类人吧. 第一类人 将lock对象定义成static,这 ...

  4. 使用StopWatch类来计时 (perf4j-0.9.16.jar 包里的类)

    public class StopWatch { static public int AN_HOUR = 60 * 60 * 1000; static public int A_MINUTE = 60 ...

  5. 数据结构和算法(Golang实现)(13)常见数据结构-可变长数组

    可变长数组 因为数组大小是固定的,当数据元素特别多时,固定的数组无法储存这么多的值,所以可变长数组出现了,这也是一种数据结构.在Golang语言中,可变长数组被内置在语言里面:切片slice. sli ...

  6. Fiddler实战之使用Fiddler模拟弱网环境(限速)

    1.模拟弱网环境 打开Fiddler,Rules->Performance->勾选 Simulate Modem Speeds,勾选之后访问网站会发现网络慢了很多 2.Fiddler弱网的 ...

  7. 002-IDE的使用与数据类型-C语言笔记

    002-IDE的使用与数据类型-C语言笔记 学习目标 1.[了解]IDE并熟悉Xcode基本使用技巧 2.[理解]C程序的入口和运行流程 3.[理解]变量的声明赋值和一些细节 4.[理解]变量的命名规 ...

  8. AJ整理问题之:NSTimer准确吗?

    NSTimer准确吗? 问题:NSTimer准确吗?如果不准确,怎么办? NSTimer的工作原理:假设timer每隔一段时间执行一次事件,很均匀的(例如每隔多少秒),假设在某一时刻cpu在做疯狂的大 ...

  9. XML布局界面

    Android推荐使用XML布局文件来定义用户界面,而不是使用Java代码来开发用户界面,因此基础所有组件都提供了两种方式来控制组件的行为:1.在XML布局文件中通过XML属性进行控制:2.在Java ...

  10. 用Python爬取大众点评数据,推荐火锅店里最受欢迎的食品

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:有趣的Python PS:如有需要Python学习资料的小伙伴可以加点 ...