首页 > 其他分享 >【oj刷题】滑动窗口篇:滑动窗口的应用场景和注意事项

【oj刷题】滑动窗口篇:滑动窗口的应用场景和注意事项

时间:2024-09-12 23:21:46浏览次数:3  
标签:子串 right 窗口 oj int ret 滑动

前言:

滑动窗口其实基本原理还是双指针,但在双指针中左右指针可能会有回退操作,而滑动窗口的左右指针只会向前走,不会回退,下面就来讲解一下滑动窗口的概念和具体操作(主要是例题讲解)

目录

一、什么是滑动窗口?

二、滑动窗口的原理

三、滑动窗口的算法实现

四、滑动窗口的例题讲解

4.1. 长度最小的子数组

4.2 无重复字符的最长子串

4.3 找到字符串中所有字母异位词


一、什么是滑动窗口?

 滑动窗口是一种动态数据结构,它包含一系列元素,这些元素按照一定的顺序排列。滑动窗口的特点是窗口的大小可以动态调整,窗口中的元素可以向前或向后滑动。

下面我们通过一道例题来具体的看一下滑动窗口是什么:

力扣209

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 

子数组

 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3]是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

提示:

  • 1 <= target <= 109
  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 105

理解完题意之后我们就来看一下下面的讲解:

以上就是滑动窗口的定义,根据滑动窗口的定义我们需要知道在使用滑动窗口必须是左右指针都不会回退,一起向前的才可以

二、滑动窗口的原理

  1. 窗口大小:滑动窗口的大小是指窗口中元素的数量。窗口大小可以是固定的,也可以是动态变化的。
  2. 窗口位置:滑动窗口的位置是指窗口在数据序列中的起始位置。
  3. 窗口滑动:当窗口向前或向后滑动时,窗口中的元素会发生变化。滑动窗口的核心思想是利用窗口中的元素进行计算或分析。

三、滑动窗口的算法实现

  1. 简单滑动窗口:假设窗口大小为k,数据序列为S,滑动窗口算法如下:

    • 初始化窗口位置为0,窗口大小为k。
    • 遍历数据序列S,计算窗口中的元素和。
    • 当窗口向前滑动时,更新窗口中的元素和。
    • 输出窗口中的元素和。
  1. 动态窗口大小:当窗口大小动态变化时,需要根据实际情况调整算法。(上面图中我们举的例子就是一个动态滑动窗口)以下是一个简单的示例:

    • 初始化窗口位置为0,窗口大小为k。
    • 遍历数据序列S,计算窗口中的元素和。
    • 当窗口向前滑动时,根据需要调整窗口大小,并更新窗口中的元素和。
    • 输出窗口中的元素和。

四、滑动窗口的例题讲解

4.1. 长度最小的子数组

这个就是上面的那个例题,算法原理我们已经讲过了,现在我们直接来看一下它的实现:

int minSubArrayLen(int target, vector<int>& nums) {
    int n = nums.size(), sum = 0, ret = INT_MAX;
    for (int left = 0, right = 0; right < n; right++)
    {
        sum += nums[right];   //进窗口
        while (sum >= target)
        {
            ret = min(ret, right - left + 1);
            sum -= nums[left++];   //出窗口
        }
    }
    return ret == INT_MAX ? 0 : ret;
}

通过这段代码我们可以看到滑动窗口一般分为这几步:

1、循环(一般是当right走到数组尾部的时候停止)

2、进窗口:在right右移时会有新的元素进到窗口里面

3、判断+出窗口:根据题意判断是否满足条件,然后让left右移让窗口中的元素出去

这几步就是滑动窗口类题的基本格式,大部分题直接套这个公式就行了,下面我们再来看几个题来巩固一下

4.2 无重复字符的最长子串

力扣3

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是"abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是"b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是"wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

提示:

  • 0 <= s.length <= 5 * 104
  • s 由英文字母、数字、符号和空格组成

题意解析:本题要求的就是一个字符串中的不重复的最长字串,题意并不难理解,值得我们思考的有一点,就是当新元素进窗口时,我们如何可以知道它窗口中已经有这个元素呢?相信你心中已经有了答案,没错,就是借助哈希表来标记窗口中已经有过的字符,且当元素种类较少时,我们可以直接借助一个整形数组来模拟哈希表,下面我们先来看一下本题的推导过程,然后再看一下代码实现:

推导过程:

代码实现:

int lengthOfLongestSubstring(string s) {
    int hash[128] = { 0 };   //使用数组来模拟哈希表
    int left = 0, right = 0, n = s.size();
    int ret = 0;
    while (right < n)
    {
        hash[s[right]]++;
        while (hash[s[right]] > 1)
        {
            hash[s[left++]]--;   //出窗口
        }
        ret = max(ret, right - left + 1);    //更新结果
        right++;    //让下一个元素进入窗口
    }
    return ret;
}

4.3 找到字符串中所有字母异位词

力扣438

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

示例 1:

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

 示例 2:

输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。

提示:

  • 1 <= s.length, p.length <= 3 * 104
  • s 和 p 仅包含小写字母

本题往简单点看就是找到字符串中的特定字串,只是并不要求顺序一致,这道题也是需要结合哈希表来实现的,跟上面的做题格式基本一致,下面我们直接来看一下代码实现:

vector<int> findAnagrams(string s, string p) {
    vector<int> ret;
    int hash1[26] = { 0 };     //统计字符串p中每个字符出现的个数
    for (auto e : p) hash1[e - 'a']++;
    int hash2[26] = { 0 };    //统计窗口里面每个字符出现的个数
    int m = p.size();
    for (int left = 0, right = 0, count = 0; right < s.size(); right++)
    {
        char in = s[right];
        if (++hash2[in - 'a'] <= hash1[in - 'a']) count++;  //进窗口+维护count
        if (right - left + 1 > m)
        {
            char out = s[left++];
            if (hash2[out - 'a']-- <= hash1[out - 'a']) count--;   //出窗口+维护count
        }
        //更新结果
        if (count == m) ret.push_back(left);
    }
    return ret;
}

感谢各位大佬观看,创作不易,还望各位大佬点赞支持!!!

标签:子串,right,窗口,oj,int,ret,滑动
From: https://blog.csdn.net/2301_80220607/article/details/142186551

相关文章

  • UNO.Skia.Gtk 设置窗口尺寸变化方法
    本文记录一个简单的在UNO.Skia.Gtk应用里面,配置GTK平台修改窗口尺寸的方法为了全平台通用性,推荐是走定义接口加平台注入的方式。定义的接口如下publicinterfaceIWindowActivator{voidResizeMainWindow(Sizesize);}这里为了方便起见,直接使用静态属性注入方法,如......
  • vue3 判断浏览器打开窗口页签变化
       场景:当需要同时打开两个页签,需要在切换页签的时候,重新获取数据    根据document.visibilityState结果判断。如果为visible则证明回到当前页签, 如果为hidden则证明当前页面未显示(前往了其他页签)import{onMounted,onUnmounted}from'vue';consthan......
  • 【转】[C#][WPF] 避免窗口最大化时遮盖任务栏
    转自:https://learn.microsoft.com/zh-cn/previous-versions/msdn10/dd366102(v=MSDN.10)WPF窗口最大化时有个很不好的现象是:如果窗口的WindowStyle被直接或间接地设置为None后(比如很多情况下你会覆盖默认的窗体样式,即不采用Windows默认的边框和最大化最等按钮,来打造个性的窗......
  • Java学习1:命令行窗口执行.java程序(自用)
    编写源代码:编译与执行:1、普通方法:生成了.class文件(字节码)2、从Java11开始,由单个文件构成的java程序,无需编译,可以直接执行。使用这种方法也不产生.class文件。该方法可快速测试程序。但源文件必须是单个的.java文件。问题:文件名与public类名是否必须相同?答:不一定......
  • UNO 设置平台进入全屏窗口模式的方法
    本文记录在UNOPlatform的桌面窗口项目里,进入和退出全屏窗口的方法,此方法包括UNO的WPF和GTK和WinUI版本的实现在2024.06的5.2.139的UNO版本里面,可通过如下简单方法进入全屏Microsoft.UI.Xaml.Windowwindow=...window.AppWindow.SetPresenter(AppWindowPrese......
  • 每日OJ_牛客_合唱团(打家劫舍dp)
    目录牛客_合唱团(打家劫舍dp)解析代码1解析代码2牛客_合唱团(打家劫舍dp)合唱团__牛客网        有n个学生站成一排,每个学生有一个能力值,牛牛想从这n个学生中按照顺序选取k名学生,要求相邻两个学生的位置编号的差不超过d,使得这k个学生的能力值的乘积最大,......
  • Alice和Bob的爱恨情仇(lanqiao OJ 3865)
    问题如下(附链接):Alice和Bob的爱恨情仇题解代码如下:#include<bits/stdc++.h>usingnamespacestd;intmain(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);intn,k;cin>>n>>k;intans=0;for(inti=0;i<n;i++){intx;cin>>......
  • LOJ4222 「IOI2024」马赛克上色 题解
    题目描述给定长为\(n\)、下标从零开始的\(01\)序列\(x,y\),保证\(x_0=y_0\)。令\(col_{0,j}=x_j,col_{i,0}=y_i\),对\(\forall1\lei\ltn,1\lej\ltn\),\(col_{i,j}=[col_{i-1,j}=0\andcol_{i,j-1}=0]\)。\(q\)次询问,给定\(u,d,l,r\),求\(\sum_{i=u}^d......
  • LeetCode算法—滑动窗口
    一:滑动窗口1、窗口:滑动窗口的核心就是一个窗口;通常使用两个指针表示(一个指向左边界;一个指向右边界);窗口中的元素就是当前字串2、滑动:窗口从数组或字符串的起始位置开始,逐步向右滑动。当窗口无法满足条件时,调整左边界以缩小窗口;当窗口满足条件时,尝试记录当前窗口的结果,并继续调整......
  • 滑动窗口&动态规划-1031. 两个非重叠子数组的最大和
    问题描述问题求解本题还挺巧妙,有点类似两数和的扩展题。对于两个线段,我们可以固定右线段,然后寻找左线段的最大值。固定右线段使用到的算法是滑动窗口,寻找左线段最大值的算法是动态规划。时间复杂度:O(n)classSolution:defmaximizeWin(self,prizePositions:List[int......