滑动窗口做题思路

什么是滑动窗口?就是一个队列,然后通过在这个队列中的各种移除和添加满足题目需求

题目:

209. 长度最小的子数组 - 力扣(LeetCode)

 

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int sum = 0;
        int n = nums.length;
        int ret = n+1;
        for(int i = 0;i<n;i++){
            sum+=nums[i];
            while(sum-nums[left] >= target){
                sum= sum-nums[left++];
            }
            if(sum>=target){
                ret = Math.min(ret,i-left+1);
            }
        }
        return ret<=n?ret:0;
    }
}

复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)

713. 乘积小于 K 的子数组 - 力扣(LeetCode)

class Solution {
    public int numSubarrayProductLessThanK(int[] nums, int k) {
        //滑动窗口
        //l  r
        //[l,r] [l+1,r]...[r,r]
        //r-1+1
        if(k<=1){
            return 0;
        }
        int n = nums.length,ans = 0,prod = 1,left = 0;
        for(int right = 0;right<n;++right){
            prod *= nums[right];
            while(prod>=k){
                prod/=nums[left++];

            }
            ans+=right-left+1;
        }
        return ans;
    }
}

本题采用的是双指针滑动窗口,大循环是右指针的移动,内部小循环是左指针的移动。

时间复杂度:O(n),其中 n 是数组 nums 的长度,右指针遍历一遍数组,左指针紧随其后最多遍历一遍数组;

空间复杂度:O(1),只创建了有限的几个常量变量作为记录。

1004. 最大连续1的个数 III - 力扣(LeetCode)

 滑动窗口 + 变量计数模板

class Solution {
    public int slidingWindow(int[] nums, int k) {
        //数组/字符串长度
        int n = nums.length;
        //双指针,表示当前遍历的区间[left, right],闭区间
        int left = 0, right = 0;
        //定义变量统计 子数组/子区间 是否有效
        int sum = 0;
        //定义变量动态保存最大 求和/计数
        int res = 0;

        //右指针遍历到数组尾
        while (right < n) {
            //增加当前右指针对应的数值
            sum += nums[right];
            //当在该区间内 sum 超出定义范围
            while (sum > k) {
                //先将左指针指向的数值减去
                sum -= nums[left];
                //左指针右移
                left++;
            }
            //到 while 结束时,我们找到了一个符合题意要求的 子数组/子串
            res = Math.max(res, right - left + 1);
            //移动右指针,去探索下一个区间
            right++;
        }
        return res;
    }
}

 

class Solution {
    public int longestOnes(int[] nums, int k) {
        int n = nums.length;
        int left = 0;
        int right = 0;
        int zeros = 0;
        int len=0;

        while(right<n){
            if(nums[right]==0){
                zeros++;
            }
            //当0个数超了,让left一直右移到满足
            while(zeros>k){
                if(nums[left]==0){
                    zeros--;
                }
                left++;
            }
            //记录符合条件的长度
            len = Math.max(len,right-left+1);
            right++;
        }
        return len;
    }
}

567. 字符串的排列 - 力扣(LeetCode)

72ms

class Solution {
    public boolean checkInclusion(String s1, String s2) {
            if (s1.length() > s2.length()) {
        return false;
    }

    int[] count1 = new int[26];
    // 统计s1中每个字符出现的次数
    for (int i = 0; i < s1.length(); i++) {
        char c = s1.charAt(i);
        count1[c - 'a']++;
    }

    // 定义滑动窗口的范围是[l,r],闭区间,长度与s1相等
    int l = 0, r = s1.length();

    while (r <= s2.length()) {
        // 统计窗口s2[l,r-1]内的元素出现的次数
        int[] count2 = new int[26];
        for (int i = l; i < r; i++) {
            char c = s2.charAt(i);
            count2[c - 'a']++;
        }

        // 如果滑动窗口内各个元素出现的次数跟 s1 的元素出现次数完全一致,返回 True
        if(Arrays.equals(count1,count2)) {
            return true;
        }

        l++;
        r++;
    }
    return false;

    }
}

效率很低23ms

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        //getOrDefault(Object key, Object defaultValues)
        //若map中存在key 则返回key对应的value值
       //否则返回默认值defaultValues

       //滑动窗口 + 两哈希,始终保证窗口长度,当长度超了,左指针准备右移

       Map<Character,Integer>need = new HashMap<>();
       Map<Character,Integer>map = new HashMap<>();

       //创建[双指针] 和 [有效变量]
       int left = 0,right = 0;
       int valid = 0;

       for(Character c:s1.toCharArray()){
            need.put(c,need.getOrDefault(c,0)+1);
       }
       while(right<s2.length()){
            char c = s2.charAt(right);
            if(need.containsKey(c)){
                map.put(c,map.getOrDefault(c,0)+1);
                if(need.get(c).equals(map.get(c))){
                    valid++;
                }
            }
            //当凑齐了元素,还要判断长度
            while(right-left+1>=s1.length()){
                if(valid==need.size()){
                    return true;
                }
                char d = s2.charAt(left);
                if(need.containsKey(d)){
                    if(need.get(d).equals(map.get(d))){
                        valid--;
                    }
                    map.put(d,map.get(d)-1);
                }
                left++;
            }
            right++;

       }
       return false;
    }
}

6ms 

#define MAX_CHAR_LENGTH 26
bool isMatch(int*hash1,int *hash2)
{
    for(int i = 0;i<MAX_CHAR_LENGTH;i++){
        if(hash1[i]!=hash2[i])return false;
    }
    return true;
}
bool checkInclusion(char* s1, char* s2) {
    if(strlen(s1)>strlen(s2))return false;
    int len1 = strlen(s1);
    int len2 = strlen(s2);
    int windowSize = len1;
    int hash1[MAX_CHAR_LENGTH];
    int hash2[MAX_CHAR_LENGTH];
    memset(hash1,0,sizeof(hash1));
    memset(hash2,0,sizeof(hash2));
    //初始化hash1,hash2
    for(int i = 0;i<windowSize;i++){
        hash1[s1[i]-'a']++;
        hash2[s2[i]-'a']++;
    }
    //首次匹配
    if(isMatch(hash1,hash2))return true;
    //s2的滑动窗口,每次右移一位,更新hash2
    for(int i = len1;i<len2;i++){
        hash2[s2[i]-'a']++;
        hash2[s2[i-len1]-'a']--;
        if(isMatch(hash1,hash2))return true;
    }
    return false;
}

5ms 

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int n = s1.length(),m = s2.length();
        if(n>m){
            return false;
        }
        int[] cnt1 = new int[26];
        int[] cnt2 = new int[26];
        for(int i =0;i<n;i++){
            ++cnt1[s1.charAt(i)-'a'];
            ++cnt2[s2.charAt(i)-'a'];
        }
        if(Arrays.equals(cnt1,cnt2)){
            return true;
        }
        for(int i=n;i<m;i++){
            ++cnt2[s2.charAt(i)-'a'];
            --cnt2[s2.charAt(i-n)-'a'];
            if(Arrays.equals(cnt1,cnt2)){
                return true;
            }
        }
        return false;
    }
}

 

3. 无重复字符的最长子串 - 力扣(LeetCode)

import java.util.HashMap;

/**
 * <h2>无重复字符的最长子串</h2>
 * <p>1.给定一个字符串s,请你找出其中不含有重复字符的最长子串的长度.</p>
 * <p>2.s由英文字母,数字,符号和空格组成</p>
 */
public class Leetcode03 {

    public int lengthOfLongestSubstring(String s){
        HashMap<Character,Integer> map = new HashMap<>();//key返回比较大用hashMap 但是这道题目仅仅是128个字符可以用数组
        int begin = 0;
        int maxLength = 0;
        for(int end = 0;end<s.length();end++){
            char ch = s.charAt(end);
            if (map.containsKey(ch)) {//重复时,调整begin
                begin = Math.max(begin,map.get(ch) + 1);//防止begin回退
                map.put(ch,end);
            }else{//没有重复
                map.put(ch,end);
            }
//            System.out.println(s.substring(begin,end+1));
            maxLength = Math.max(maxLength,end - begin +1);
        }
        return maxLength;
    }

    public static void main(String[] args){
//        System.out.println(new Leetcode03().lengthOfLongestSubstring("abcabcbb"));
        Leetcode03 e02 = new Leetcode03();
//        System.out.println(e02.lengthOfLongestSubstring("abcabcbb"));
        System.out.println(e02.lengthOfLongestSubstring("abba"));
        /*
            [(a,0),(b,2)]
             b
               e
            abba
         */



         /*
            a
            ab
            abc
            bca
            cab
            abc
            cb
            b
          */

        /*
            给定一个字符串 s ,请你找出其中不含重复字符的最长子串的长度
            abcabcbb   3
            a
            ab
            abc
            bca
            cab
            abc
            cb
            b

            bbbbbb      1
            b

            pwwkew      3
            p
            pw
            w
            wk
            wke
            kew

            [(a,3),(b,7),(c,5)]
                 b
                   e
            abcabcbb

        要点:
            1.用 begin 和 end 表示子串开始和结束位置
            2.用hash表检查重复字符
            3.从左到右查看每一个字符,如果:
                - 没遇到重复字符,调整end
                - 遇到重复的字符,调整begin
                - 将当前字符放入hash表
            4.end - begin + 1 是当前子串长度
         */

    }
}

 76. 最小覆盖子串 - 力扣(LeetCode)

 16ms

class Solution {
    public String minWindow(String S, String t) {
        //这道题目大写小写都有直接创建128大小的数组,保证所有ASCII字符都可以统计
        char[] s = S.toCharArray();
        int m = s.length;
        int ansLeft = -1;
        int ansRight=m;
        int left = 0;
        int[] cntS =new int[128];//s子串字母出现次数
        int[] cntT = new int[128];//t中字母出现次数
        for(char c:t.toCharArray()){
            cntT[c]++;
        }
        for(int right =0;right<m;right++){//移动子串右端点
            cntS[s[right]]++;//右端点字母移入子串
            while(isCovered(cntS,cntT)){//涵盖
                if(right-left<ansRight-ansLeft){//找到更短的子串
                    ansLeft = left;
                    ansRight =right;
                }
                cntS[s[left++]]--;//左端点字母移出子串
            }
        }
        return ansLeft<0?"":S.substring(ansLeft,ansRight+1);
     }
     private boolean isCovered(int[] cntS,int[] cntT){
        for(int i ='A';i<='Z';i++){
            if(cntS[i] < cntT[i]){
                return false;
            }

        }
        for(int i ='a';i<='z';i++){
            if(cntS[i] < cntT[i]){
                return false;
            }

        }
        return true;
        
     }
}

 13ms

class Solution {
    public String minWindow(String s, String t) {
        // 参数校验
        if (s == null || t == null || s.length() < t.length()) {
            return "";
        }
        // 保存t字符出现的次数,表示每个字符待需要的数量
        Map<Character, Integer> tMap = new HashMap<>(t.length());
        for (int i = 0; i < t.length(); i++) {
            tMap.put(t.charAt(i), tMap.getOrDefault(t.charAt(i), 0) + 1);
        }
        // 判断窗口是否包含了t的所有元素,避免每次去遍历tMap,增加耗时
        int needCnt = t.length();
        // 定义最小结果集时的左右边界,初始化边界长度为最大值
        int[] minResult = new int[]{0, Integer.MAX_VALUE};
        int length = s.length();
        // 定义滑动窗口左右边界,右边界开始移动
        for (int i = 0, j = 0; j < length; j++) {
            char c = s.charAt(j);
            // 包含t,待需要的数量减一
            if (tMap.getOrDefault(c, 0) > 0) {
                needCnt--;
            }
            // 同时map需要的字符数量减一
            tMap.put(c, tMap.getOrDefault(c, 0) - 1);
            // 都包含了,此时右边界j不动,开始移动左边界,尝试缩小窗口
            if (needCnt == 0) {
                
                while (true) {
                    c = s.charAt(i);
                    // 左边界字符已经满足了,不再需要了,则退出循环,没办法继续缩小了
                    // 否则继续缩小,那么会执行下面的+1,所需要的字符又增加了
                    if (tMap.get(c) == 0) {
                        break;
                    }
                    // 左边界字符
                    // map还有多余数量可以缩小
                    // 缩小左边界,该字符所需要的数量+1
                    tMap.put(c, tMap.getOrDefault(c, 0) + 1);
                    i++;
                }
                // 左边界也更新完了,这时该更新结果了,覆盖res
                if (j - i < minResult[1] - minResult[0]) {
                    minResult[1] = j;
                    minResult[0] = i;
                }
                c = s.charAt(i);
                //将左边界右移,执行下一个窗口
                // 由于左边界是t需要的字符,右移后,需要更新tMap和needCnt,表示还需要增加一个字符
                tMap.put(c, tMap.getOrDefault(c, 0) + 1);
                needCnt++;
                i++;
            }
        }
        // 超过边界,返回空串
        if (minResult[1] > length) {
            return "";
        } else {
            return s.substring(minResult[0], minResult[1] + 1);
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面向对象设计与分析40讲(25)中介模式、代理模式、门面模式、桥接模式、适配器模式

文章目录 门面模式代理模式中介模式 之所以把这几个模式放到一起写&#xff0c;是因为它们的界限比较模糊&#xff0c;结构上没有明显的差别&#xff0c;差别只是语义上。 这几种模式在结构上都类似&#xff1a; 代理将原本A–>C的直接调用变成&#xff1a; A–>B–>…

Java面试八股之marshalling和demarshalling

marshalling和demarshalling Marshalling&#xff08;序列化&#xff09;是将内存中的对象状态转化为适合传输或存储的格式&#xff08;如字节流、JSON、XML&#xff09;&#xff0c;以便进行网络通信、持久化存储或跨平台/语言交互操作。Demarshalling&#xff08;反序列化&a…

spring aop介绍

Spring AOP&#xff08;面向切面编程&#xff09;是一种编程范式&#xff0c;它允许开发者将横切关注点&#xff08;cross-cutting concerns&#xff09;从业务逻辑中分离出来&#xff0c;从而提高代码的模块化。在传统的对象导向编程中&#xff0c;这些横切关注点&#xff0c;…

【分治】Leetcode 颜色分类

题目讲解 75. 颜色分类 这道题的本质就是数组分三块 算法讲解 使用三个指针&#xff0c;i遍历数组&#xff0c;left标记0的最右侧&#xff0c;right标记2的最左侧 如果当前的nums[i] 0,我们就让nums[left] 和 nums[i]位置上的数字做交换&#xff0c;这里的i是可以向前移…

基于51单片机的宠物自动喂食语音播报,有实物

1. 51仿真&#xff1a; LCD第一屏显示食物重量&#xff0c;当前时间&#xff0c;温湿度。第二屏显示喂食时间&#xff0c;第三屏显示喂食重量。可通过点击查看喂食时间翻转屏幕显示。 点击查看喂食时间后&#xff0c;显示喂食时间&#xff0c;可以设置三个时间&#xff0c;再点…

【做一名健康的CSDNer】程序员哪几种行为最伤肾(程序员必看)

虽然没有专门针对程序员这一职业群体特有的伤肾行为的研究报道&#xff0c;但根据一般人群的健康风险和生活习惯&#xff0c;程序员由于其特殊的工作模式和环境&#xff0c;可能更容易出现如下伤肾的行为&#xff1a; 熬夜加班&#xff1a; 程序员由于项目进度、bug修复等原因&…

面试十八、容器适配器

容器适配器是一种特殊类型的容器&#xff0c;它们提供了一种不同于常规容器的接口和行为。容器适配器通常是建立在其他容器之上&#xff0c;通过改变接口或添加限制来满足特定的需求或解决特定的问题。 在 C 中&#xff0c;标准库提供了三种常见的容器适配器&#xff1a; 栈&am…

《HCIP-openEuler实验指导手册》1.3Apache动态功能模块加载卸载练习

1.3.1 配置思路 mod_status 模块可以帮助管理员通过web界面监控Apache运行状态&#xff0c;通过LoadModule指令加载该模块&#xff0c;再配置相关权限&#xff0c;并开启ExtendedStatus后&#xff0c;即可使用该模块。 1.3.2 配置步骤 检查mod_status模块状态&#xff08;使…

用户成功故事汇源达投顾选股软件见证智 慧投资的辉煌篇章

在投资领域&#xff0c;每一个成功的投资者背后&#xff0c;往往都有一款值得信赖的选股软件作为他们的得力助手。而河北源达的“财源滚滚”选股软件&#xff0c;正是这样一款备受投资者赞誉的智能投资工具。今天&#xff0c;我们就来分享一些使用财源滚滚选股软件获得成功的用…

【数学建模】虫子追击问题(仿真)

已知 有四个虫子,分别是 A , B , C , D A,B,C,D A,B,C,D A , B , C , D A,B,C,D A,B,C,D分别在 ( 0 , 0 ) , ( 0 , 1 ) , ( 1 , 1 ) , ( 1 , 0 ) (0,0),(0,1),(1,1),(1,0) (0,0),(0,1),(1,1),(1,0)四个虫子A追B&#xff0c;B追C&#xff0c;C追D&#xff0c;D追A四个速度相同 …

【UnityShader】图片圆角

1.需求 我们在开发的时候&#xff0c;有时候一些按钮或者菜单栏的边角是直角的需要改成圆角&#xff0c;但是让美术重新绘制耽误时间不说也确实没必要&#xff0c;这个时候我们不妨使用一个简单的shader去解决这个问题&#xff0c;下面我们就讲讲这个shader要如何实现。 需求1…

【智能算法】闪电搜索算法(LSA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2015年&#xff0c;H Shareef等人闪电自然现象启发&#xff0c;提出了闪电搜索算法&#xff08;Lightning Search Algorithm, LSA&#xff09;。 2.算法原理 2.1算法思想 LSA受到闪电梯级先导传…

c++取经之路(其七)——c++的内存管理new与delete

c的基本的内存管理一般就是用new和delete来管理 new与delete&#xff1a; 我们直接来将用法&#xff0c;我一般用new有两种用法&#xff0c;一种只申请一个这样的数据&#xff0c;另一种是申请多个这样的数据&#xff0c;比如我们要申请一个int&#xff0c;和申请十个int&…

MQTT服务器EMQX的安装和使用(Windows)

一、下载地址&#xff1a; 下载 EMQX 二、安装环境&#xff1a; Windows Server2016 16G 500G 三、启动服务&#xff1a; 下载文件解压后放入以下目录&#xff08;注意&#xff0c;目录名一定是英文&#xff0c;否则会造成启动不成功&#xff01;&#xff09;&#xff1a…

Linux实现标准输入和标准输出(STDIN_FILENO和STDOUT_FILENO)

在C语言中&#xff0c;scanf和printf函数用于标准输入和标准输出的输入输出操作。而在Linux中&#xff0c;STDIN_FILENO和STDOUT_FILENO是用于表示标准输入和标准输出的文件描述符。 STDIN_FILENO和STDOUT_FILENO是定义在头文件 <unistd.h> 中的常量&#xff0c;用于表示…

【C语言进阶】指针例题大杂烩,阁下是高手还是菜鸟?

前言 首先说明&#xff0c;本文不适合新手&#xff0c;如果你刚刚接触指针&#xff0c;可以看看前五点&#xff0c;这是我认为指针中比较重要的细节&#xff0c;例题部分酌情尝试。 如果你自认为指针学的不错&#xff0c;胸有成竹&#xff0c;请尝试最后的例题&#xff0c;如…

空间转录组SODB数据库(补充)

SODB数据库 SODB facilitates comprehensive exploration of spatial omics data | Nature Methods https://db.cngb.org/stomics/ a–f&#xff0c; SODB的整体设计。六个六边形总结了SODB的六个特点。SODB包含各种类型的空间组学数据&#xff08;a&#xff09;&#xff0c…

C++心决之类和对象详解(中篇)(封装入门二阶)

目录 1.类的6个默认成员函数 2. 构造函数 2.1 概念 2.2 特性 3.析构函数 3.1 概念 3.2 特性 4. 拷贝构造函数 4.1 概念 4.2 特征 5.赋值运算符重载 5.1 运算符重载 5.2 赋值运算符重载 5.3 前置和后置重载 7.const成员 8.取地址及const取地址操作符重载 1.类的…

Linux 目录遍历函数

目录遍历函数 DIR *opendir(const char *name); struct dirent *readdir(DIR *dirp); int closedir(DIR *dirp);// 打开一个目录 #include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name);参数&#xff1a;- name: 需要打开的目录的名称返回值…

Spring AI教程(二)Chat API之基于数据库的多Key轮询

基于数据库的多Key轮询 在之前的文章中我们所使用的Key都是一个&#xff0c;但事实上&#xff0c;官方对Key会有一定的请求限制&#xff0c;在实际业务场景下&#xff0c;我们也不可能通过一个Key来保证我们的系统稳定运行&#xff0c;因为一旦超过请求限制&#xff0c;就会出现…