今天是算法数据结构专题的第2篇文章,我们一起来学习一下「滑动窗口算法」。

前言

最近刷到leetCode里面的一道算法题,里面有涉及到Sliding windowing算法,因此写一篇文章稍微总结一下


算法题介绍

没有重复字符的子字符的最大长度:给一个字符串,获得没有重复字符的最长子字符的长度

例子:

输入:"abcabcbb"

输出:3

解释:因为没有重复字符的子字符是'abc',所以长度是3

解法1:暴力解法

    public class Solution {//时间复杂度高O(n3)
public int lengthOfLongestSubstring(String s) {
int n = s.length();
int ans = 0;
//遍历所有的子字符串,记录没有重复字母的子字符串的最大的长度
//获取子字符串时,使用两个标签,分别代表子字符串的开头和结尾
for (int i = 0; i < n; i++)
for (int j = i + 1; j <= n; j++)
//当子字符串没有重复字母时,ans记录最大的长度
if (allUnique(s, i, j)) ans = Math.max(ans, j - i);
return ans;
}
//判断该子字符串是否有重复的字母
public boolean allUnique(String s, int start, int end) {
//HashSet实现了Set接口,它不允许集合中出现重复元素。
Set<Character> set = new HashSet<>();
for (int i = start; i < end; i++) {
Character ch = s.charAt(i);
if (set.contains(ch)) return false;
set.add(ch);
}
return true;
}
}

分析

时间复杂度:O(n3).

解法2:滑动窗口算法

通过使用HashSet作为一个滑动窗口,检查一个字符是否已经存在于现有的子字符中只需要O(1).

滑动窗口经常作为一个抽象的概念来处理数组/字符串问题。窗口代表着一组数据/字符串元素,通过开头和结尾的索引来定义窗口。

public class Solution {//时间复杂度O(2n)
//滑动窗口算法
public int lengthOfLongestSubstring(String s) {
int n = s.length();
Set<Character> set = new HashSet<>();
int ans = 0, i = 0, j = 0;
while (i < n && j < n) {//窗口的左边是i,右边是j,下列算法将窗口的左右移动,截取出其中一段
// try to extend the range [i, j]
if (!set.contains(s.charAt(j))){//如果set中不存在该字母,就将j+1,相当于窗口右边向右移动一格,左边不动
set.add(s.charAt(j++));
ans = Math.max(ans, j - i);//记录目前存在过的最大的子字符长度
}
else {//如果set中存在该字母,则将窗口左边向右移动一格,右边不动,直到该窗口中不存在重复的字符
set.remove(s.charAt(i++));
}
}
return ans;
}
}

分析

时间复杂度:O(2n)。在最差的情况下,每个字符将会被访问两次

解法3:优化的滑动窗口算法

上面的滑动窗口算法最多需要2n的步骤,但这其实是能被优化为只需要n步。我们可以使用HashMap定义字符到索引之间的映射,然后,当我们发现子字符串中的重复字符时,可以直接跳过遍历过的字符了。

public class Solution {//时间复杂度o(n)
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
//使用hashmap记录遍历过的字符的索引,当发现重复的字符时,可以将窗口的左边直接跳到该重复字符的索引处
Map<Character, Integer> map = new HashMap<>(); // current index of character
// try to extend the range [i, j]
for (int j = 0, i = 0; j < n; j++) {//j负责向右边遍历,i根据重复字符的情况进行调整
if (map.containsKey(s.charAt(j))) {//当发现重复的字符时,将字符的索引与窗口的左边进行对比,将窗口的左边直接跳到该重复字符的索引处
i = Math.max(map.get(s.charAt(j)), i);
}
//记录子字符串的最大的长度
ans = Math.max(ans, j - i + 1);
//map记录第一次遍历到key时的索引位置,j+1,保证i跳到不包含重复字母的位置
map.put(s.charAt(j), j + 1);
}
return ans;
}
}

分析

时间复杂度:O(n)

滑动窗口算法总结

  • 滑动窗口算法可以用以解决数组/字符串的子元素问题
  • 滑动窗口算法可以将嵌套的for循环问题,转换为单循环问题,降低时间复杂度

文章出处

什么是「滑动窗口算法」(sliding window algorithm),有哪些应用场景?的更多相关文章

  1. 滑动窗口协议(Sliding Window Protocol)

    滑动窗口协议(Sliding Window Protocol),属于TCP协议的一种应用,用于网络数据传输时的流量控制,以避免拥塞的发生.该协议允许发送方在停止并等待确认前发送多个数据分组.由于发送方 ...

  2. 滑动窗口的中位数 · Sliding Window Median

    [抄题]: 给定一个包含 n 个整数的数组,和一个大小为 k 的滑动窗口,从左到右在数组中滑动这个窗口,找到数组中每个窗口内的中位数.(如果数组个数是偶数,则在该窗口排序数字后,返回第 N/2 个数字 ...

  3. 洛谷——P1886 滑动窗口|| POJ——T2823 Sliding Window

    https://www.luogu.org/problem/show?pid=1886#sub || http://poj.org/problem?id=2823 题目描述 现在有一堆数字共N个数字( ...

  4. Sentinel滑动窗口算法

    在前面搞清楚了Sentinel的使用后,大致理了一下Sentinel的责任链,搞清楚了这个,基本就已经梳理清楚sentinel-core模块的大部分内容,顺着这条链路可以继续梳理很多东西. 知其然.知 ...

  5. 【算法数据结构专题】「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现延时队列的开发实战落地(上)

    承接上文 承接之前的[精华推荐 |[算法数据结构专题]「延时队列算法」史上非常详细分析和介绍如何通过时间轮(TimingWheel)实现延时队列的原理指南],让我们基本上已经知道了「时间轮算法」原理和 ...

  6. ST算法 Sliding Window algorithm template

    ST算法(Sliding Window):A easy way to slove the substring problems algorithm template to slove substrin ...

  7. 精华推荐 |【算法数据结构专题】「延时队列算法」史上非常详细分析和介绍如何通过时间轮(TimingWheel)实现延时队列的原理指南

    时间轮的介绍 时间轮(TimeWheel)是一种实现延迟功能(定时器)的精妙的高级算法,其算法应用范围非常广泛,在Java开发过程中常用的Dubbo.Netty.Akka.Quartz.ZooKeep ...

  8. [LeetCode] Sliding Window Median 滑动窗口中位数

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

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

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

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

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

随机推荐

  1. AtCoder Beginner Contest 329 (ABC329)

    A. Spread 不说了,代码. B. Next 不说了,代码. C. Count xxx Description 给定一个长度为 \(N\) 的字符串 \(S\),求 \(S\) 中非空连续,并且 ...

  2. 比较Spring Security6.X 和 Spring Security 5.X的不同

    项目使用了SpringBoot3 ,因此 SpringSecurity也相应进行了升级 版本由5.4.5升级到了6.1.5 写法上发生了很大的变化,最显著的变化之一就是对 WebSecurityCon ...

  3. C#/.NET/.NET Core推荐学习书籍(已分类)

    前言 古人云:"书中自有黄金屋,书中自有颜如玉",说明了书籍的重要性.作为程序员,我们需要不断学习以提升自己的核心竞争力.以下是一些优秀的C#/.NET/.NET Core相关学习 ...

  4. Element的安装与基本使用

    一.什么是Element? Element是饿了么团队研发的一套为开发者与设计师等准备的基于Vue2.0的桌面端组件库,使开发人员可以快速拼凑出一套页面 组件:组成网页的部件,例如:超链接,按钮,图片 ...

  5. jmeter完成文件上传接口

    前提:测试项目中有一个上传本地文件(excel)测被测接口. 测试工具:jmeter 协议:http 测试项目如下图: 第一步:点击模板上传,选择本地excel文件 第二步:上传成功,系统识别exce ...

  6. java中的try-with-resource语法

    java的世界千奇百怪...当我甩出如下代码段,不知阁下如何应对? try(A a=new A()){ 和a变量无关的业务代码块 } 没错,这就是"臭名昭著"的try-with-r ...

  7. # C# 重新认识一下 IEnumerable<T>,IAsyncEnumerable<T> 以及搭配异步可能遇到的问题

    C# 重新认识一下 IEnumerable<T>,IAsyncEnumerable<T> 以及搭配异步可能遇到的问题 前言 为啥会想到写这个 为了这碟醋,包了这顿饺子 作为老鸟 ...

  8. spring cloud生态中Feign、Ribbon、loadbalancer的一些历史

    背景 本意是想写个feign中loadbalancer组件和nacos相遇后,一个兼容相关的问题,后面发现Feign这套东西很深,想一篇文章写清楚很难,就先开一篇,讲历史. Feign.OpenFei ...

  9. AI换脸利器!Roop下载分享

    ​ 前段时间给大家介绍过换脸界最强的Rope,感兴趣的小伙伴可以戳戳手指 传送门:https://blog.csdn.net/S_eashell?spm=1011.2415.3001.5343 今天要 ...

  10. 组合式api的使用方式

    方式一:通过setup选项 <script> export default { setup(){ // 提供数据 // 提供函数 // 提供计算属性等等..... } } </scr ...