算法:滑动窗口

文章目录

  • 例题1:长度最小的子数组
  • 例题2:无重复字符的最长子串
  • 例题3:最大连续1的个数 III
  • 例题4:将 x 减到 0 的最小操作数
  • 例题5:水果成篮
  • 例题6:找到字符串中所有字母异位词
  • 例题7:串联所有单词的子串
  • 例题8:最小覆盖子串

例题1:长度最小的子数组

长度最小的子数组

在这里插入图片描述
分析:
若暴力枚举,用三重循环列出所有可能:

int n = nums.size();
for(int i = 0; i < n; i++){//以i位置开头的所有子数组
	for(int j = i; j < n; j++){//以j位置为结尾
		int n = 0;
		for(int k = i; k <= j; k++){//依次算出各个子数组的和,然后比较和大于等于target的子数组的长度那个最小
			n += nums[k];
………………………………………………………………
//时间复杂度 O(N^3)

简单的优化:计算子数组和时不需要每次都从头开始

int n = nums.size();
for(int i = 0; i < n; i++){//以i位置开头的所有子数组
	int n = 0;
	for(int j = i; j < n; j++){
		n += nums[j];
	
//时间复杂度 O(N^2)

因为这道题说数组中的数全为正整数,所以 += 操作后 n 肯定是递增的(单调性) —— 当 n >= target 时就没有继续 += 的必要了,此时 n 就是这个循环中 长度最小的、和大于等于target的子数组的和

以 2 3 1 2 4 3(target = 7) 为例,第一层循环过后,我们知道了以0位置开头的子数组中,2 3 1 2 是我们想要的;第二次循环会从3开始,我们需要再从头开始枚举子数组吗 —— 我们可以记录第一次循环结束位置,然后直接以3 1 2为基础继续

● 根据以上的分析,我们改用两个指针(同向双指针(同向指两个指针都不回退,向着一个方向移动))来实现上述的操作:
在这里插入图片描述

left 和 right 两个“指针”之间形成一个区间,并记录(维护)着这个区间内的信息(子数组和、长度),两个指针从左向右移动的过程中,这个区间就像一个窗口一样在数组中滑动 —— 滑动窗口

以上的思路为:利用单调性,使用“同向双指针(滑动窗口)”优化问题

● 怎么用:
1.left = 0,right = 0
2.进窗口
3.判断 <-> 出窗口

● 这个方法的正确性:
利用单调性,规避了很多没有必要的枚举行为

在暴力解法中若发现了单调性,可以考虑用这个方法

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size(), sum = 0, len = INT_MAX;//结果
        for(itn left = 0, right = 0; right < n; right++){
            sum += nums[right];//进窗口(新进入left和right之间的数据,会产生什么影响--sum+=nums[right])
            while(sum >= target)//判断
            {
                len = min(len, right - left + 1);//更新结果 -- 可能在判断后,也可能在出窗口后(因题而异)
                sum -= num[left++];//出窗口(left++过后,左侧数据不再处于left和right之间)
            }
        }
        return len;
    }
};

● 时间复杂度:
我们的每一步操作都让 left / right 向右移动,直至最后 -> O(N)

例题2:无重复字符的最长子串

无重复字符的最长子串

在这里插入图片描述
暴力解法:暴力枚举(从左往右依次枚举以左侧数字为开头的满足要求的所有子串)-- 判断满足要求:可以用哈希表储存已遍历子串部分的字符,依次判断字符是否重复

模拟:
在这里插入图片描述

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int hash[128] = {0};//使用数组模拟哈希表,0表示没有,1出现一次,2出现两次
        int len = 0;
        for(int left = 0, right = 0; right < s.size(); right++){
            hash[s[right]]++;//进窗口
            while(hash[s[right]] > 1)//判断 
                hash[s[left++]]--;//出窗口
            len = max(len, right - left + 1);//更新结果
        }
        return len;
    }
};

例题3:最大连续1的个数 III

最大连续1的个数 III

在这里插入图片描述

问题转化:找出0的个数不超过k个的最长子数组

暴力求解:从左往右依次以每个数为开头,往后找最长可以到哪 ->O(N^2)
模拟示例1:
在这里插入图片描述

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int ret = 0;
        for(int left = 0, right = 0, zero = 0; right < nums.size(); right++){//zero记录0的个数
            //对于right而言,1进窗口时不用管
            if(nums[right] == 0) zero++;//0进窗口
            while(zero > k)//判断
                if(nums[left++] == 0) zero--;//出窗口
            ret = max(ret, right - left + 1);//更新结果
        }
        return ret;
    }
};

例题4:将 x 减到 0 的最小操作数

将 x 减到 0 的最小操作数

在这里插入图片描述
分析:
在这里插入图片描述

正 难 则 反

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        //题目说了nums[i]>0
        int sum_ = 0;
        for(auto e : nums) sum_+= e;
        int target = sum_ - x;
        if(target < 0) return -1;//!
        int n = nums.size(), len = -1;
        for(int left = 0, right = 0, sum = 0; right < n; right++){
            sum += nums[right];//入窗口
            while(sum > target){//判断
                sum -= nums[left++];//出窗口       
            }
            if(sum == target) 
                len = max(len,right - left + 1);//更新结果
        }
        return len == -1 ? -1 : n - len;//如果len初始被赋予 0,这地方用len == 0做判断,遇到 target == 0 的情况会出问题
    }
};

例题5:水果成篮

水果成篮

在这里插入图片描述

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        int n = fruits.size();
        int hash[100001] = {0};//数组模拟哈希表,表示各水果类型所持数目 
        //也可以用unordered_map,似乎更方便些
        
        //题目说 1 <= fruits.length <= 10^5,结果开10010个空间不给过,合着 <= 10^5的意思是数量级不是具体数呗,这个老六
        int num = 0, sort = 0;
        for(int left = 0, right = 0; right < n; right++){
            if(hash[fruits[right]] == 0) sort++;
            hash[fruits[right]]++;//入窗口
            while(sort > 2){
                if((--hash[fruits[left++]]) == 0)//出窗口
                    sort--;
            }
            num = max(num, right - left + 1);
        }
        return num;
    }
};

这个方法我和老师写的几乎一模一样 —— 我终于出息了(

老师用哈希表的演示:

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        unordered_map<int, int> hash;
        int ret = 0;
        for(int left = 0, right = 0; right < fruits.size(); right++){
            hash[fruits[right]]++;//进窗口
            while(hash.size() > 2){
                //出窗口
                hash[fruits[left]]--;
                if(hash[fruits[left]] == 0)
                    hash.erase(fruits[left]);
                left++;
            }
            ret = max(ret, right - left + 1);
        }
        return ret;
    }
};

例题6:找到字符串中所有字母异位词

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

在这里插入图片描述
不同于之前的题目的是,这道题的滑动窗口是固定长度的(长度为p的大小)

可以用两个哈希表分别表示 p 中每个字符出现的次数 和 滑动窗口中每个字符出现的次数。通过比较两哈希表是否相同判断异位词

在这里插入图片描述

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int hash1[26] = {0};//p中每个字符出现的次数
        for(auto ch : p) hash1[ch-'a']++;
        int hash2[26] = {0};//滑动窗口中每个字符出现的次数
        vector<int> ret;
        for(int left = 0, right = 0, count = 0; right < s.size(); right++){
            char in = s[right];//进窗口的字符 
            hash2[in - 'a']++;//进窗口
            if(hash2[in - 'a'] <= hash1[in - 'a']) 
                count++;
            //判断
            if(right - left >= p.size()){//固定的窗口长度:p.size()
                char out = s[left++];
                if(hash2[out - 'a']-- <= hash1[out - 'a']) count--;//出窗口
            }
            if(count == p.size()) ret.push_back(left);//更新结果
        }
        return ret;
    }
};

例题7:串联所有单词的子串

串联所有单词的子串

在这里插入图片描述

例题6 的加强版,试着将子串当做一整个数据(就像单个字符一样)

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        unordered_map<string, int> hash1;//存储 words 中的子串
        for(auto& str : words) hash1[str]++;
        int len = words[0].size();//一个子串的长度,可视作一个整体数据
        vector<int> ret;
        for(int i = 0; i < len; i++){//自不同的起点出发遍历所有情况
            unordered_map<string, int> hash2;//维护滑动数组内的子串
            for(int left = i, right = i, count = 0; right + len <= s.size(); right += len){
                string in = s.substr(right, len);//进窗口的子串
                hash2[in]++;//进窗口
                if(hash1.count(in) && hash2[in] <= hash1[in]) count++;
                if(right - left >= len * words.size()){
                    string out = s.substr(left, len);//出窗口的数据
                    if(hash1.count(out) && hash2[out] <= hash1[out]) count--;
                    hash2[out]--;
                    left += len;//出窗口
                }
                if(count == words.size()) ret.push_back(left);
            }
        }
        return ret;
    }
};

例题8:最小覆盖子串

最小覆盖子串

在这里插入图片描述

分析:
在这里插入图片描述

class Solution {
public:
    string minWindow(string s, string t) {
        int hash1[58] = { 0 };//开了57个空间,然后不够……建议直接开128个空间,还省去了后面 -'A' 的麻烦
        for (auto ch : t) hash1[ch - 'A']++;
        int hash2[58] = { 0 };
        int begin = -1, len = INT_MAX;
        for (int left = 0, right = 0, count = 0; right < s.size(); right++) {
            char in = s[right];//进窗口数据
            hash2[in - 'A']++;//进窗口
            if (hash2[in - 'A'] <= hash1[in - 'A']) count++;
            while (count == t.size()) {//判断
                if (right - left + 1 < len) {//更新结果
                    len = right - left + 1;
                    begin = left;
                }
                char out = s[left];//出窗口数据
                if (hash2[out - 'A'] <= hash1[out - 'A']) count--;
                hash2[out - 'A']--;//出窗口
                left++;
            }
        }
        return len == INT_MAX ? "" : s.substr(begin, len);
    }
};

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

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

相关文章

网络工程技术-学习内容(非技术文)

公共基础双纹线的制作 认识网络环境 (1)ipv4 ipv4地址的构成&#xff0c;分类&#xff0c;子网刻分&#xff0c;超丽素合“ 交换机的基本配置telnet&#xff0c;ssh&#xff0c; web方式三种配置 van. sto.协议 VLAN 端口聚合 三层交换“ 路由器的基本配置《(端口 IP 地址配)《…

msvcp120.dll丢失的解决方法,教你快速解决msvcp120.dll问题

msvcp120.dll是一个在Windows操作系统中至关重要的系统文件&#xff0c;它属于Microsoft Visual C Redistributable Package的一部分。这个动态链接库文件&#xff08;DLL&#xff09;包含了运行某些应用程序所必需的C运行时库函数。当某个程序在运行过程中需要调用这些预先编译…

requests做接口测试

Requests 是用Python语言编写&#xff0c;基于 urllib&#xff0c;采用 Apache2 Licensed 开源协议的 HTTP 库。它比 urllib 更加方便&#xff0c;可以节约我们大量的工作&#xff0c;完全满足 HTTP 测试需求。Requests 的哲学是以 PEP 20 的习语为中心开发的&#xff0c;所以它…

rabbitmq基础(1)

1、背景 能实现消息队列的框架软件有很多&#xff0c;kafka、rabbitmq、RocketMq、activeMq、Redis&#xff08;非专业&#xff09;&#xff0c;各有各的特点和优缺点。但是之前的公司数据需求规模并非很大&#xff0c;所以采用rabbitmq作为消息队列。 2、rabbitMq的基础架构…

工业网关、物联网网关与PLC网关是什么?

网关是什么&#xff1f; 网关是一种用于连接不同网络的网络设备&#xff0c;其作用是实现网络之间的通信和数据交换。它负责将一个网络的数据转发到另一个网络&#xff0c;并且可以进行路由、转换和过滤等处理。通常用于连接局域网和广域网之间&#xff0c;可以是硬件设备或者软…

基于javaweb实现的学生选课系统

一、系统架构 前端&#xff1a;jsp | bootstrap | jquery | css 后端&#xff1a;spring | sprinmvc | mybatis 环境&#xff1a;jdk1.8 | mysql | maven | tomcat 二、代码及数据库 三、功能介绍 01. 登录页 02. 管理员-课程管理 03. 管理员-学生管理 04. 管…

网络编程:select、poll

.1、select完成TCP并发服务器 程序代码&#xff1a; #include <myhead.h> #define SER_IP "192.168.125.234" //服务端IP #define SER_PORT 8888 //服务端端口号int main(int argc, const char *argv[]) {//1.创建用于连接的套接字int sfds…

C#,电话数字键盘问题(Mobile Numeric Keypad problem)的算法与源代码

1 电话数字键盘问题 提供移动数字键盘。您只能按向上、向左、向右或向下至当前按钮的按钮。不允许您按最下面一行的角点按钮&#xff08;即.*和#&#xff09;。 移动键盘 给定一个数N&#xff0c;找出给定长度的可能数。 示例&#xff1a; 对于N1&#xff0c;可能的数字数为…

免费SSL证书有效期

免费SSL证书有效期现状 目前市场上主流的免费SSL证书提供商大多遵循行业规范&#xff0c;将免费证书的有效期设为3个月。这意味着每隔三个月&#xff0c;网站管理员必须重新申请、验证并安装新的SSL证书&#xff0c;以维持网站的HTTPS安全连接状态。这种做法已成为行业的常态&…

GEE入门篇|图像分类(一):非监督分类

在非监督分类中&#xff0c;我们有与监督分类相反的过程。 首先对光谱类进行分组&#xff0c;然后将其分类为簇。因此&#xff0c;在 Earth Engine 中&#xff0c;这些分类器是 ee.Clusterer 对象。 它们是“自学”算法&#xff0c;不使用一组标记的训练数据&#xff08;即它们…

C++复习笔记——泛型编程模板

01 模板 模板就是建立通用的模具&#xff0c;大大提高复用性&#xff1b; 02 函数模板 C另一种编程思想称为 泛型编程 &#xff0c;主要利用的技术就是模板 C 提供两种模板机制:函数模板和类模板 函数模板语法 函数模板作用&#xff1a; 建立一个通用函数&#xff0c;其函…

centos上部署k8s

环境准备 四台Linux服务器 主机名 IP 角色 k8s-master-94 192.168.0.94 master k8s-node1-95 192.168.0.95 node1 k8s-node2-96 192.168.0.96 node2 habor 192.168.0.77 镜像仓库 三台机器均执行以下命令&#xff1a; 查看centos版本 [rootlocalhost Work]# cat /…

2024腾讯Java面试题精选,教你抓住面试的重点

重要 大环境对于我们能力要求越来越高&#xff0c;医学专家又说今年冬天新冠肺炎将“席卷重来”。 如果疫情再次爆发&#xff0c;势必将再次影响企业的正常运作&#xff0c;一波裁员浪潮你又能否抗住&#xff1f; 不管如何&#xff0c;明年金三银四又是一波跳槽时机&#xf…

数字化时代的新里程碑:Web3的革命

在当今数字化时代&#xff0c;Web3正成为了一股强大的力量&#xff0c;重新定义了我们对互联网的认知。本文将深入探讨Web3的定义、特点&#xff0c;以及它对金融、供应链、社交媒体等领域的革命性影响&#xff0c;并展望Web3的未来发展。 1. Web3的定义与特点 Web3不仅是一种…

力扣206反转链表

206.反转链表 力扣题目链接(opens new window) 题意&#xff1a;反转一个单链表。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 1&#xff0c;双指针 2&#xff0c;递归。递归参考双指针更容易写&#xff0c; 为什么不用头插…

无代理方式实现VMware的迁移?详细解析

在当今数字化时代&#xff0c;数据的安全性和可用性对于企业至关重要。尤其是在VMware转变订阅策略后&#xff0c;原本永久订阅的产品转变为以年付费订阅的形式&#xff0c;导致客户不得不支付更多的费用&#xff0c;大幅增加了成本。同时&#xff0c;客户也对VMware未来发展前…

计算机图形学的作用

计算机图形学的作用 计算机图形学的作用1.创造数字世界2.物理世界的仿真模拟2.1 三维几何2.2 物理动态2.3 人体运动2.4 虚实融合 3.仿真模拟与智能应用 笔记来源&#xff1a;GAMES001-图形学中的数学 计算机图形学的作用 1.创造数字世界 计算机图形学创造数字世界 数字世界…

FEP容量瓶多应用于制药光电光伏行业

常用规格&#xff1a;25ml、50ml、100ml、250mlFEP容量瓶也叫特氟龙容量瓶&#xff0c;容量瓶是为配制一定物质的量浓度的溶液用的精确定容器皿&#xff0c;常和移液管配合使用。广泛用于ICP-MS、ICP-OES等痕量分析以及同位素分析等高端实验。地质、电子化学品、半导体分析测试…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:TapGesture)

支持单击、双击和多次点击事件的识别。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 接口 TapGesture(value?: { count?: number, fingers?: number }) 参数&#xff1a; 参数名称参数类型必填参…

【Android Studio】的矢量绘图【pathData】详解

目录&#xff1a; 例子老师&#xff1a;一、基础知识&#xff1a;1、命令和常数&#xff1a;2、绝对坐标和相对坐标&#xff1a; 一、落笔命令命令Mx&#xff0c;y和mx&#xff0c;y&#xff08;大小写绝对和相对&#xff09; 二、画直线命令Lx&#xff0c;y和lx&#xff0c;y&…