算法通过村第十六关-滑动窗口|青铜笔记|滑动很简单

news2024/12/20 2:27:58

文章目录

  • 前言
  • 滑动窗口的基本思想
  • 入门题目练习
    • 子数组最大平均数
    • 最长连续递增序列
  • 总结


前言


提示:我宁愿做自己,做卑微的自己,也不愿做别人,无论那会多么快乐。 --《美丽新世界》

我们在数组和链表的部分就已经接触到了双指针的思想,这里我们继续扩展了解滑动窗口的思想。滑动窗口其实也是双指针的一种特殊场景,这种方式可以很好的解决一些特定场景的问题,就有了”滑动窗口思想“

滑动窗口的基本思想

在数组和链表的章节,都强调过移动元素的方法。有一些经典的例子,推荐回顾再看一下⭐⭐⭐:

算法通过村第三关-数组白银笔记|数组双指针_师晓峰的博客-CSDN博客

算法通关村第一关-链表白银挑战笔记|公共子节点_师晓峰的博客-CSDN博客

于是慢慢的方式更加完善,这就有了”双指针的思想“

在数组双指针里,我们介绍过”对撞型”、“快慢型“两种方式,而滑动窗口思想其实也就是快慢型的特例。我们在学习计算机网络的同学都直到欢动窗口协议(Sliding Window Protocol),该协议是TCP实现流量控制等核心策略之一。事实上与流量控制,熔断、限流、超时等场景下都会首先从滑动窗口的角度来思考问题,比如Hystrix,sentinel等框架都使用了这种思想。

滑动窗口的思想非常简单,如下图,假如窗口的大小是3,当不断有新数据来的时候,我们便维护一个大小为3的一个区间,超过3的就将新的加入,老的移走。

这个过程有点像火车在轨道上行驶,原始数据可能在一个很大的空间里(铁轨),但是我们标记的小区间就像是一列固定长度的过车,一直再向前走。

有了区间,造其题目来就很容易了,例如让你找序列上连续数字的最大和最小,或者平均数,等等问题把

在这里插入图片描述
从上面看,刚才的形容是不是非常形象,所谓的窗口就是建立两个索引,left和right,并保持{left,right}之间的长度不变,然后一遍遍历,一遍寻找目标,每次更改目标要求就可以。

当然上面的例子已经告诉我们什么是窗口,什么是滑动的窗口:

  • 窗口:窗口其实就是两个变量left和right之间的元素,也可以理解为一个区间。窗口的大小可能是固定的,也可能是变换的,如果是固定大小的,那么自然要考虑是否越界,在执行处理逻辑。如果不是固定的,就要优先判断是否满足要求,再执行逻辑处理。
  • 滑动:说明这个窗口是移动的,事实上移动的仍然是left和right两个变量,而不是序列中的元素。当变量移动的时候,其中间的元素必然也会发生变化,因此就有了不断滑动的效果。

在实际问题中,窗口大小不一定是固定的,我们可以思考以下两种场景:

  1. 固定窗口的滑动就是火车行驶这种大小不变的移动
  2. 可变的窗口就是两个老师带着一队学生外出,一个负责开路,一个负责断后,中间则是小朋友。两个老师直接的距离有可能大有可能小,但是整体窗口是不断滑动向前的

所以根据窗口大小是否固定,就衍生出两种类型的题目:

  1. 固定窗口:一般让你求那个窗口的元素最大,最小、平均值、和最大、和最小等等类型的问题。
  2. 窗口变化:则一般是让你求序列最大、最小窗口是什么等等。

滑动窗口题目本身没有很大难度,但是在实际的解答中还是比较难搞的,主要是以下原因:

  1. 容器:数组,让人头疼的边界问题,稍不注意,就全盘皆输。
  2. 元素处理:比较、判断等处理方式上不仅需要借助集合等工具,还要处理技巧,不熟悉的话拿不下来。
  3. 堆:堆的接口很适合做数据处理。在固定的区间找最大、最小等问题上有很大优势。一次常常滑动窗口会和堆一起使用完美的解决很多复杂问题。

最后的疑惑:双指针和滑动窗口有什么区别?

根据性质可以看出,滑动窗口就是双指针应用的特例,主要是关注两个指针间的元素情况,因此范围更小,双指针的应用范围更广,花样更多。

入门题目练习

滑动窗口的题目在于窗口的大小变或者不变,根据这两种类型,我们就先来练练手吧.

子数组最大平均数

参考题目介绍:643. 子数组最大平均数 I - 力扣(LeetCode)

在这里插入图片描述
在这里插入图片描述
这是经典的滑动窗口的例子,况且大小都规定了,我们只要先读取k个,然后让窗口向前移动就可以了,思路和上图一模一样.

直接展示代码:

    /**
     * 子数组最大平均数 I
     * @param nums
     * @param k
     * @return
     */
    public static double findMaxAverage(int[] nums, int k) {
        int len = nums.length;
        if ((k > len) || (len < 1) || (k < 1)) {
            return 0;
        }
        // 第一步确定窗口大小
        int windowSum = 0;
        for (int left = 0; left < k; left++) {
            windowSum += nums[left];
        }
        // 第二步 遍历维护窗口  保留窗口,处理元素
        int res = windowSum;
        for(int right = k; right < len; right++){
            windowSum += (nums[right] - nums[right - k]);
            res = Math.max(res,windowSum);
        }
        return (double) res / k;
    }

最长连续递增序列

参考题目介绍:674. 最长连续递增序列 - 力扣(LeetCode)

在这里插入图片描述
在这里插入图片描述
根据实例我们看图:

在这里插入图片描述
可以看到,最长的递增子序列为{1,3,5},所以返回3.在遍历的时候从第第一个元素开,先定义窗口区间[left,right),

表示递增序列,具体操作如下:

  1. 如果当前遍历到的元素比左边的那个元素要严格大,right就增加;
  2. 相反,left就跳到right的其实位置,重新计算.

这里看下代码怎么写:

/**
 * 674. 最长连续递增序列
 * @param nums
 * @return
 */
public static int findLengthOfLCIS_1(int[] nums) {
   int len = nums.length;;
   int left = 0,right = 0;
   int res = 0;
   while(right < len){
       // 严格递增 right++
       // 相反 right 赋值给left (本质也是快慢指针问题
       if (right >0 && nums[right - 1] >= nums[right]){
           left = right;
       }
       right++;
       res = Math.max(res,right - left);
   }
   return res;
}

上面的代码中,序列在[left,right)下严格递增,区间的长度是right-left.

这里还有很多解法,另外一种简单的思路是一遍遍历,一边统计每个递增区间的长度.如果长度超过之前所有的区间,就保留,代码写起来也很容易:

    /**
     * 674. 最长连续递增序列
     *
     * @param nums
     * @return
     */
    public static int findLengthOfLCIS_2(int[] nums) {
        int currentSum = 1;
        int res = 1;
        for (int i = 1; i < nums.length; i++) {
            if (nums[i - 1] >= nums[i]) {
                // 说明不满足条件,重新计数
                currentSum = 1;
            }else{
                currentSum++;
            }
            res = Math.max(res, currentSum);
        }
        return res;
    }

当然本题目你如果不知道滑动窗口,也可以做的,不要觉得它过于神秘,只是个名字而已,掌握方法,看透本质才是主要的.


总结

提示:滑动窗口;双指针;快慢指针变体;滑动窗库概念;滑动窗口核心理解


如果有帮助到你,请给题解点个赞和收藏,让更多的人看到 ~ ("▔□▔)/

如有不理解的地方,欢迎你在评论区给我留言,我都会逐一回复 ~

也欢迎你 关注我 ,喜欢交朋友,喜欢一起探讨问题。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1121552.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IMX6ULL开发——第一个驱动程序

实现第一个应用程序&#xff1a;在IMX6ULL开发板上运行驱动程序hello_drv_test hello_drv_test #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h>/** ./hel…

生产者消费者模式(c++实现)

生产者消费者模式思路就是&#xff1a;一批专门生产资源的线程 和一批专门处理资源的线程以及一个线程安全的任务队列组成的 。并且当任务队列满的时候阻塞生产线程&#xff0c;任务队列为空的时候阻塞消费线程。 要实现一个生产者消费者队列 1。需要实现线程同步&#xff0c;…

react的setState做了什么

1、为什么需要setState setState的作用是帮助我们更改数据的同时并且通知视图进行渲染。因为React并不会绑定视图和state&#xff0c;需要我们手动去更新视图。 2、setState什么时候是同步的&#xff0c;什么时候是异步的 setState这个方法在调用的时候是同步的&#xff0c;…

如果面试问到你redis的常用数据类型,你怎么和面试官聊上十分钟?

最近组长把一些简历推到我这边让我帮他面试几份&#xff0c;问到这种基础题目时收到的回答总是不太理想 1、最简单的回答&#xff1a; Redis存储的是key-value结构的数据&#xff0c;其中key是字符串类型&#xff0c;value有5种常用的数据类型&#xff1a; 字符串 string哈希 …

为什么spring默认采用单例bean

概 述 熟悉 Spring开发的朋友都知道 Spring 提供了 5种 scope&#xff0c;分别是&#xff1a; singleton: 单例模式&#xff0c;当spring创建applicationContext容器的时候&#xff0c;spring会欲初始化所有的该作用域实例&#xff0c;加上lazy-init就可以避免预处理&#xf…

磁盘分区如何分? 电脑磁盘分区免费软件指南!

列出并比较顶级免费磁盘分区管理器软件&#xff0c;以选择适用于 Windows 的最佳分区软件&#xff1a; 系统分区在现代计算机设备中起着非常重要的作用。它们可以存储数据&#xff0c;使系统文件远离用户数据&#xff0c;并在同一台设备上安装多个操作系统。但是&#xff0c;这…

MyBatis-Plus 实战教程一

这里写目录标题 简介快速上手数据库建立创建实体类修改参数引入依赖测试常见注解介绍TableNameTableIdTableField 常见配置仓库地址 简介 MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;…

qt-C++笔记之信号与槽

qt-C笔记之信号与槽 code review! 本文抄自公众号&#xff1a;嵌入式小生 文章目录 qt-C笔记之信号与槽一.信号2.1.信号的发出2.2.信号的处理 二.槽函数2.1.带有默认参数的信号和槽函数2.2.使用QObject::connect()将信号连接到槽函数的三种方法2.2.1.第一种方法&#xff1a;使…

整理MongoDB文档:身份验证

整理MongoDB文档:身份验证 个人博客&#xff0c;求关注。 文章概叙 本文主要讲MongoDB在单机状态下的账户配置。理解了MongoDB的语法&#xff0c;对于如何配置用户权限会知道怎么配置&#xff0c;但是请注意给谁配置什么权限才是最重要的。 最小权限原则 系统的每个程序或者…

【C++编程语言】STL常用算法 算术生成和集合算法

1.算术生成算法概念 算法简介&#xff1a; accumlate 计算容器元素累计总和fill 向容器中添加元素 注意&#xff1a;算术生成算法属于小型算法 使用时包含头文件为#include<numeric> 2.accumulate /*函数原型&#xff1a;int accumulate(iterator beg ,iterator end…

热点不热!如何修复笔记本电脑未连接到移动热点的问题

当你远离常规Wi-Fi时,移动热点是让你的笔记本电脑上网的关键,但当它没有按计划运行时,你会怎么办?以下是Windows笔记本电脑无法连接到移动热点时的几种修复方法。 为什么我的笔记本电脑没有连接到我的热点 由于你的笔记本电脑正试图连接到另一个有限制和可能存在问题的设…

前端学成在线项目详细解析二

12-banner区域-课程表布局 HTML布局 <div class"right"><h3>我的课程表</h3><div class"content">1</div> </div> CSS样式 /* 课程表 */ .banner .right {margin-top: 60px;width: 218px;height: 305px;background-…

STM32F4_照相机

目录 前言 1. BMP编码 2. JPEG编码 前言 我们所要实现的照相机&#xff0c;支持BMP图片格式的照片和JPEG图片格式的照片。 1. BMP编码 BMP文件是由文件头、位图信息头、颜色信息和图形数据四部分构成。 1. BMP文件头&#xff08;14个字节&#xff09;&#xff1a;BMP文件…

在ESP32-Arduino开发中添加其它Arduino库

目录 前言 原理说明 操作步骤 下载Bounce 安装Bounce 将下载的文件夹(压缩包需要解压)移动到components/arduino/libraries路径下&#xff0c;并重命名为Bounce2 查看添加库里所有的源文件位置 在arduino的CMakeList.txt里添加库源文件 使用Bounce 前言 乐鑫官方的es…

HTTP介绍 原理 消息结构 客户端请求 服务器响应 HTTP状态码

一、HTTP介绍二、HTTP工作原理HTTP三点注意事项 三、HTTP消息结构四、客户端请求消息五、服务器响应消息HTTP请求方法 七、HTTP响应头信息八、HTTP状态码&#xff08;HTTP Status Code&#xff09;下面是常见的HTTP状态码&#xff1a;HTTP状态码分类HTTP状态码列表 一、HTTP介绍…

旁注、目录越权、跨库查询、cdn绕过

原理&#xff1a; 搭建网站多IP多端口&#xff0c;更多一个域名多网站&#xff0c;IIS的在属性-高级里面设置主机头设置域名&#xff0c;域名是收费的需要自己买一个 旁注&#xff1a;在同一服务器上有多个站点&#xff0c;要攻击的这个站点假设没有漏洞&#xff0c;可以攻击…

Spark大数据分析与实战笔记(第一章 Scala语言基础-5)

文章目录 每日一句正能量章节概要1.5 Scala的模式匹配与样例类1.5.1 模式匹配字符匹配匹配字符串守卫匹配类型匹配数组、元组、集合 1.5.2 样例类 课外补充偏函数 每日一句正能量 “成功的秘诀&#xff0c;在于对目标的执着追求。”——爱迪生 无论是在工作、学习、还是生活中&…

控制台的设置

目录 win32 API &#xff1a; 什么是API &#xff1a; 控制台&#xff1a; 控制台与VS&#xff1a; 控制台的控制&#xff1a; 控制台窗口设置&#xff1a; 1、mode函数&#xff1a; 2、title 函数&#xff1a; 在C语言中的实现&#xff1a; 控制台的坐标设置&#…

python 之numpy 之随机生成数

文章目录 1. **生成均匀分布的随机浮点数**&#xff1a;2. **生成随机整数**&#xff1a;3. **生成标准正态分布随机数**&#xff1a;4. **生成正态分布随机数**&#xff1a;5. **生成均匀分布的随机浮点数**&#xff1a;6. **生成随机抽样**&#xff1a;7. **设置随机数种子**…

Linux下Samba服务安装及启用全攻略

Linux下Samba服务安装及启用全攻略 前言一、安装SSH Server二、安装Samba Server1.安装net-tool2.建立账号的samba3.windows通过Samba与linux共享文件4.使用远程工具登录Linux 总结 前言 提示&#xff1a;本文详解了在Linux系统下如何安装和启用Samba服务&#xff0c;涵盖了从…