初识算法 · 滑动窗口(3)

news2025/4/15 5:07:34

目录

前言:

水果成篮

题目解析

算法原理

算法编写

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

题目解析

算法原理

算法编写


前言:

​本文的主题是滑动窗口,通过两道题目讲解,一道是水果成篮,一道是找到字符串中的所有字母异位词。
链接分别为:
904. 水果成篮 - 力扣(LeetCode)

438. 找到字符串中所有字母异位词 - 力扣(LeetCode)
题目分为三个部分讲解,一是题目解析,二是算法原理,三是算法编写,那么,话不多说,直接进行主题咯。


水果成篮

题目解析

做这道题目不亚于做一道阅读理解,但是这道题本身就是属于高中的,题目又臭又长,但是题目要求确实很简单,所以根据题目描述,我们可以将题目总结为一句话,从一个数组里面选取两个数组成的最长子数组,就可以了,那么和之前做到最大的连续个数1基本上没有区别,所以暴力解法也就是一直遍历,确定起点,往后遍历到非A或B的数就可以了。此时的时间复杂度是标准的O(N^2),那么代码编写就同学们下来自己实现咯。

算法原理

算法原理就非常简单了,需要一个变量判断种类,所以引入变量,又因为数的范围是10的五次方

所以引入的hash表为100001,并且是固定的三部曲,进窗口的时候维护kind,如果最开始为0,那么没有该水果种类,就可以直接kind++,++之后,就是判断,判断条件自然就是如果kind大于水果种类的话,就出窗口,就是自然的left++什么的咯,此时同时要维护kind,也就是如果哈希表的映射变为0了,那么kind就--,算法原理就这么多,没有特别要注意的。

算法编写

class Solution 
{
public:
    int totalFruit(vector<int>& fruits) 
    {
        int hash[100001] = { 0 };
        int ans = 0, kinds = 0;
        for(int left = 0,right = 0; right < fruits.size(); right++)
        {   
            //进窗口
            if(hash[fruits[right]]++ == 0) kinds++;
            //判断             
            while(kinds > 2)
            {
                if(--hash[fruits[left++]] == 0) kinds--;        
            }
            //更新结果
            ans = max(ans, right - left + 1);
        }
        return ans;
    }
};

此时的时间复杂度是O(N),运行的时间也是比较快的:


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

题目解析

题目要求的很简单,返回所有异位词的起始索引就可以了。

那么首先我们要搞清楚一个点,什么是异位词

比如abc,异位词就是将abc进行排列组合之后组成的字符串,这就叫做异位词。那么我们判断某个字串是不是异位词难道是需要将所有的字符串进行比对吗?

高中的排列相信大家都是学习了,当然知道一个字符串排列之后的数字有多么庞大,所以我们不会一个一个比较,我们使用的第一种方法是使用哈希表映射,之后会对哈希表进行优化。

题目要求也是没有要特别注意的,现在就进入算法原理部分。

算法原理

算法一眼判定为滑动窗口,因为我们是用一个连续的区间,来和另一个连续的区间进行比较,那么正常的就是进窗口,出窗口,进行判断,进窗口自然是使用right指针,进窗口之后。

什么时候出窗口呢?

当然是right和left的区间的长度大于了目标字符串的长度,此时需要出窗口,左边出窗口即可。

但是有个难题是,如何判断区间的字符串是否目标字符串的异位词呢?

这里我们不妨使用哈希映射,统计目标字符串中字符出现的频次,第一个哈希表用来计算目标字符串出现的字母频次,第二个哈希表用来计算左右区间出现的字符频次,最后比较两个哈希表是否相等就可以了。

那么出窗口的时候,如果目标字符的频次变成了0,就肯定是要删除该元素的,所以需要erase,这里对容器使用不太熟练的同学自然需要看看文档。

此时那么出窗口之后,两个哈希表判断是否相等,相等更新结果就可以了。

这是使用哈希表解决。那么优化我们放在算法编写里面。

算法编写

class Solution 
{
public:
    vector<int> findAnagrams(string s, string p) 
    {
        vector<int> ans;
        unordered_map<char,int> hash1;//哈希表1
        unordered_map<char,int> hash2;//哈希表2
        for(auto e : p) hash1[e]++;//哈希表1判断p字符串的频次
        //滑动窗口
        for(int left = 0, right = 0; right < s.size(); right++)
        {
            //进窗口
            hash2[s[right]]++;
            //判断是否需要出窗口
            if((right - left + 1) > p.size())
            {
                //出窗口
                char out = s[left];
                if(--hash2[out] == 0) hash2.erase(out);
                left++;
            }
            //更新结果
            if(hash1 == hash2)
            ans.push_back(left);
        }
        return ans;
    }
};

当我们通过了之后,时间复杂度居然是有点高的,这里实际上是因为哈希表的删除增加是有点费时间的,我们进行hash[]++的时候,如果没有这个元素,哈希表会插入该元素,消耗的时间就有点高了。所以我们可以进行修改,使用数组模拟实现哈希表。

使用数组模拟哈希表,我们需要注意的点是:

第一,字母只有26个,并且都是小写的,所以我们第一个数组只需要开26个空间就可以了。

第二,更新结果之前的判断我们应该另外引入一个变量,因为没有函数能直接判断两个数组相等,所以我们引入变量的目的是用来计算有效字符的个数因为对于异位词来说,有效字符的个数就是相当于排序之后的任意字符串的一个一致结果,所以可以使用Int变量统计即可。

class Solution 
{
public:
    vector<int> findAnagrams(string s, string p) 
    {
        vector<int> ans;
        int hash1[26];//哈希表1
        int hash2[26];//哈希表2
        int kinds = 0;//统计有效字符的个数
        for(auto e : p) hash1[e - 'a']++;//哈希表1判断p字符串的频次
        //滑动窗口
        for(int left = 0, right = 0; right < s.size(); right++)
        {
            //进窗口
            if(++hash2[s[right] - 'a'] <= hash1[s[right] - 'a'])
            kinds++;
            //判断是否需要出窗口
            if(right - left + 1 > p.size())
            {
                //出窗口
                char out = s[left++];
                if(hash2[out - 'a']-- <= hash1[out - 'a']) kinds--;
            }
            //更新结果
            if(kinds == p.size())
            ans.push_back(left);
        }
        return ans;
    }
};

第三就是下标要记得-'a',并且进窗口需要维护kinds,出窗口仍然需要维护kinds,在后面有一道题也是,进窗口需要维护计数器,出窗口也需要维护计数器。

此时的运行时间就提起来了:


感谢阅读!

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

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

相关文章

(Linux驱动学习 - 11).Input 子系统

一.Input 子系统的定义 input 就是输入的意思&#xff0c;因此 input 子系统就是管理输入的子系统&#xff0c;和 pinctrl、 gpio 子系统 一样&#xff0c;都是 Linux 内核针对某一类设备而创建的框架。比如按键输入、键盘、鼠标、触摸屏等 等这些都属于输入设备&#xff0c;不…

聊聊 Facebook Audience Network 绑定收款账号的问题

大家好&#xff0c;我是牢鹅&#xff01;本篇是Facebook开发者系列的第五篇&#xff0c;最近看见好多群友在群里问这个&#xff0c;说Facebook的变现账户在绑定国内的银行账户时&#xff08;有些用户反馈就算不是国内的卡也会出现该问题&#xff09;&#xff0c;显示“无法绑定…

05 django管理系统 - 部门管理 - 修改部门

04我们已经实现了新增部门的功能&#xff0c;下面开始修改部门模块的实现。 按道理来说&#xff0c;应该是做成弹框样式的&#xff0c;通过ajax悄咪咪的发数据&#xff0c;然后更新前端数据&#xff0c;但是考虑到实际情况&#xff0c;先用页面跳转的方式实现&#xff0c;后面…

【含文档】基于Springboot+Vue的旅游信息管理系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

QSettings 使用详解

QSettings 类是 Qt 框架中的一个重要类&#xff0c;用于存储和访问应用程序的设置和配置。它提供了一种简单的方法来读取和写入应用程序的配置数据&#xff0c;支持多种存储格式&#xff0c;包括 Windows 注册表、INI 文件和 XML 文件等。 主要功能 1. 存储设置&#xff1a;可…

PDF在线编辑器推荐!一站式解决PDF编辑难题!

当你要对PDF文件进行编辑时&#xff0c;一款PDF编辑器就十分重要。今天小编就为大家推荐几款PDF编辑器&#xff0c;有在线的&#xff0c;也有本地的&#xff0c;大家可以根据自己的需求体验选择&#xff01; Foxit PDF Edit 直达链接&#xff1a;editor.foxitsoftware.cn Fo…

大舍传媒-海外媒体发稿:为您打造全球品牌影响力

大舍传媒-海外媒体发稿&#xff1a;为您打造全球品牌影响力 在当今全球化的商业环境中&#xff0c;企业若想在激烈的市场竞争中脱颖而出&#xff0c;拓展全球市场&#xff0c;提升品牌影响力至关重要。大舍传媒的海外媒体发稿服务&#xff0c;正是您实现这一目标的得力助手。 …

某宝228滑块 请求头 bx_pp、bx_et、以及slide接口中参数n值。90%左右的成功率,轨迹不会爆,需要的联系

声明&#xff1a; 该文章为学习使用&#xff0c;严禁用于商业用途和非法用途&#xff0c;违者后果自负&#xff0c;由此产生的一切后果均与作者无关。 本文章未经许可禁止转载&#xff0c;禁止任何修改后二次传播&#xff0c;擅自使用本文讲解的技术而导致的任何意外&#xff…

PostgreSQL学习笔记:学习总结

一、架构 1. 常驻进程&#xff08;Postmaster&#xff09; 管理后端的常驻进程&#xff0c;默认监测UNIX Domain Socket和TCP/IP&#xff08;Windows等一部分平台只监测TCP/IP&#xff09;的5432端口&#xff0c;等待前端连接处理&#xff0c;监测的端口号可在设置文件postgre…

基于腾讯云的AI视频课程制作工具

1. 需求信息 1.1 需求背景 讲师们在制作视频的过程中&#xff0c;发现录制课程比较麻烦&#xff0c;要保证环境安静&#xff0c;保证录制过程不出错&#xff0c;很容易反复重复录制&#xff0c;为了解决重复录制的工作量&#xff0c;想通过 ai 课程制作工具&#xff0c;来解决…

注册安全分析报告:北外网校

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

【软考】设计模式之中介者模式

目录 1. 说明2. 应用场景3. 结构图4. 构成5. 适用性6. 优点 1. 说明 1.用一个中介对象来封装一系列的对象交互。2.中介者使各对象不需要显式地相互引用&#xff0c;从而使其耦合松散&#xff0c;而且可以独立地改变它们之间的交互。3.中介者模式&#xff08;Mediator Pattern&…

Qt-自定义控件鼠标事件键盘事件定时器绘图

1. 自定义控件 1.1 创建自定义控件 1.在项目目录上右键&#xff0c; 选择 "Add New" 2.选择 "Qt" --> "Qt 设计师界面类" 3.根据需求选择模板&#xff0c;此处选择空窗口 4.设置类名 和 相关文件名 使用设计师界面类会产生三个文件&…

媒界:插混VS增程:魏牌蓝山用天花板Hi4诠释都市家庭用车最优解

在新能源混动领域&#xff0c;关于插混、增程谁才是混动最优解&#xff0c;一直业内争论的焦点。正如路遥知马力、日久见人心。对于新能源动力系统的评判标准来说&#xff0c;最好的答案就是路上见。 近日&#xff0c;一位媒体博主驾驶着魏牌全新蓝山从阿拉善到武汉往返狂飙30…

Python面向对象编程:封装和私有属性④

文章目录 1. 引言2. 什么是封装&#xff1f;3. 公有属性和方法4. 私有属性和方法5. 属性访问器&#xff08;Getters 和 Setters&#xff09;6. 使用 property 函数7. 综合示例7.1 项目结构7.2 模块代码__init__.pystudent.pycourse.pymanager.py 7.3 主程序代码main.py 7.4 运行…

cmake模板-支持编译动态/静态文件

代码链接&#xff1a;代码仓库 git clone https://gitee.com/etsuyou/cmake-template.git模板 模板截图 如何使用 在src和inc中写代码 此处用我默认提供的代码 ./go.sh cmake 生成Makefile ./go.sh make 生成bin文件和.a以及.so ./go.sh run app 运行 ./go.sh clean 以…

Tomcat服务部署及优化

一、Tomcat的基本介绍 1. tomcat是什么&#xff1f; Tomcat服务器是一个免费的开放源代码的Web应用服务器&#xff0c;属于轻量级应用服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c;是开发和调试JSP程序的首选。一般来说&#xff0c;T…

QT QML 练习8-Simple Transformations

简单的转换&#xff08;Simple Transformations&#xff09; 转换操作改变了一个对象的几何状态。QML元素对象通常能够被平移&#xff0c;旋转&#xff0c;缩放。下面我们将讲解这些简单的操作和一些更高级的用法。 我们先从一个简单的转换开始。用下面的场景作为我们学习的开始…

Python学习100天第9天之面向对象进阶

1 前言 在前面的章节我们已经了解了面向对象的入门知识&#xff0c;知道了如何定义类&#xff0c;如何创建对象以及如何给对象发消息。为了能够更好的使用面向对象编程思想进行程序开发&#xff0c;我们还需要对Python中的面向对象编程进行更为深入的了解。 2 property装饰器…

AVLTree 旋转笔记(根据平衡因子插入的公式,贼好理解)

平衡因子 avltree是一棵每个节点的左右子树的高度差不超过1的二叉树搜索树&#xff0c;对于avltree最重要的就是对平衡因子的控制。 对于旋转我们重点要注意的是三个节点&#xff0c;以左旋举例&#xff0c;需要注意的就是parent&#xff0c;subr&#xff0c;subrl。而旋转的方…