首页 > 编程语言 >算法——滑动窗口(day7)

算法——滑动窗口(day7)

时间:2024-07-22 23:28:48浏览次数:12  
标签:right int day7 个数 算法 hash1 哈希 滑动 left

904.水果成篮 

904. 水果成篮 - 力扣(LeetCode)

 题目解析:

根据题意我们可以看出给了我们两个篮子说明我们在开始采摘到结束的过程中只能有两种水果的种类,又要求让我们返回收集水果的最大数目,这不难让我们联想到题目的另一层意思:求最长连续子数组,条件为不超过两种水果种类。

老规矩,我们先用暴力解法寻找优化过渡到滑动窗口。

right在遍历的过程中不仅要记录水果种类还需要记录个数,所以这里我们用哈希表作为辅助,当我们水果种类超出限制时那说明得进行第二轮的对比了。第二轮开始left往前一位,那么right是否也要复位呢?——不需要,因为第二轮right复位开始也只有两种结果,要么水果种类不变,要么水果种类变小,所以是完全没必要复位的,留在原位即可。而这个优化也引出了我们的滑动窗口算法。

算法解析:

滑动窗口流程图:

只要水果种类还没超标,那就让right继续遍历的同时用hash记录数据。当水果种类超标的时候就移动left减少水果数量,直到有一种类的水果数量为0删除该种类即可继续收录新的水果种类。最后记录长度完成解答。

代码:

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        //建立哈希表<水果种类,水果数量>
        unordered_map<int, int>hash;
        int n = fruits.size();
        int ret = INT_MIN;
        for (int left = 0, right = 0; right < n; right++)
        {
            //种类不足,扩充窗口(移动right)以及哈希表收集数据
            hash[fruits[right]]++;
            //若种类仍不足则跳到下一循环开始扩充窗口
            //若超出种类,缩小窗口
            while (hash.size() > 2)
            {
                //减掉对应种类上的数量
                hash[fruits[left]]--;
                //判断当水果数量为0时删除该种类
                if (hash[fruits[left]] == 0)
                {
                    hash.erase(fruits[left]);
                }
                //移动left,缩小窗口
                left++;
            }
            //记录长度
            ret = max(ret, right - left + 1);
        }
        return ret;
    }
};

用数组模拟哈希表版本: 

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        //数组模拟哈希表
        int hash[100000] ={0};
        //记录种类
        int kind = 0;
        int n = fruits.size();
        int ret = INT_MIN;
        for (int left = 0, right = 0; right < n; right++)
        {
            if(hash[fruits[right]]==0) kind++;
            hash[fruits[right]]++;
            //若种类仍不足则跳到下一循环开始扩充窗口
            //若超出种类,缩小窗口
            while (kind > 2)
            {
                //减掉对应种类上的数量
                hash[fruits[left]]--;
                //判断当水果数量为0时删除该种类
                if (hash[fruits[left]] == 0)
                {
                    kind--;
                }
                //移动left,缩小窗口
                left++;
            }
            //记录长度
            ret = max(ret, right - left + 1);
        }
        return ret;
    }
};

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

438. 找到字符串中所有字母异位词 - 力扣(LeetCode)

题目解析:

本题难点之一就在于异位词,但我们总不可能列举所有的情况来一一对比,这肯定是会超时的。

所以我们转换一下思路:用哈希表记录字符串p里面各个字符出现的次数。然后再用另一个哈希表记录字符串s中一定范围内各个字符出现的次数。最终对比两哈希表推出正确结果。

所以最终问题转换为:遍历整个字符串,找出两哈希表一致的子串,记录起始位置。

我们在这里由于字符串p的限定只能3个字符串3个字符串进行判定不满足字符个数时right开始移动遍历并让哈希表辅助记录字符个数。当遍历的字符个数刚好时(这里为ccb,3个字符)对比两个哈希表,无论结果如何进入第2轮。

那么第二轮开始时right是前进好呢?还是复位?——前进(过渡到滑动窗口),因为前面已经录入哈希表中了,复位还得重新修改哈希表得不偿失。然后left前进之前删减哈希表数据并保持窗口长度,以此类推最后返回结果。~

算法解析:

本题与之前接触过的题都有些许不同,其一是这次的滑动窗口是固定长度的,其二是运用了两个哈希表进行辅助~

除此之外还需要介绍一下如何对比两个哈希表:

我们定义一个count变量来作为hash1中的有效个数(两表中能相对应的字符个数)

滑动窗口流程图:(因为步骤有点多,草草画一下)

 一些常规操作咱们就不讲了,这里主要来说一下:

当我们要录入hash1的时候需要判断录入的字符是否为有效个数(count),判断方法就是如果在hash1中该字符个数<=hash2中该字符个数,那就说明在录入后能够成为与hash2抵消该字符个数的可能,则count+1。

当我们要删减hash1的时候需要判断删减的字符在删减后是否影响有效字符个数,我们拿(c,c,b,a)举例,假如我们要删除第一个c的时候那么hash1里面的c还能和hash2里的c抵消吗?——可以的,那么就说明有效个数不会变,即hash1中该字符个数<hash2中该字符个数,count才会变化,因为在小于的时候无法抵消。

代码:

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        //记录字符串s的数据
        unordered_map<int, int>hash1;
        //记录字符串p的数据
        unordered_map<int, int>hash2;
        vector<int> ret;
        //录入p数据
        for (auto ch : p)
        {
            hash2[ch - 'a']++;
        }
        //记录字符串p中字符个数
        int m = p.size();
        //有效个数(用于抵消hash2)
        int count = 0;
        for (int left = 0, right = 0; right < s.size(); right++)
        {
            //把字符串s中的字符录入hash1中
            hash1[s[right] - 'a']++;
            //判断录入字符是否为有效个数
            if (hash1[s[right] - 'a'] <= hash2[s[right] - 'a'])
            {
                //如果发现该字符有增长到抵消hash2的可能,即为有效个数
                count++;
            }
            //判定结束先观察窗口长度,如果长度不够则跳到下一循环扩充窗口
            //如果窗口长度过长,缩小窗口
            if (right - left + 1 > m)
            {
                //先删减hash1中的字符个数
                hash1[s[left] - 'a']--;
                if (hash1[s[left] - 'a'] < hash2[s[left] - 'a'])
                {
                    //如果发现在删减后出现无法抵消hash2中字符的可能,则减小该有效个数
                    count--;
                }
                //缩小窗口
                left++;

            }
            //这里减完长度肯定达到标准了,可以开始对比两哈希表是否一致
            if (count == m)
            {
                //hash1中的有效个数可以抵消掉hash2中个数,记录结果
                ret.push_back(left);
            }
        }
        return ret;

    }
};

标签:right,int,day7,个数,算法,hash1,哈希,滑动,left
From: https://blog.csdn.net/fax_player/article/details/140617372

相关文章

  • 数据结构-绪论2(算法,时间复杂度)
    算法的基本概念算法是什么       程序=数据结构+算法算法的五个特性有穷性确定性可行性输入输出算法的复杂度时间复杂度算法时间复杂度事前预估算法时间开销T(n)与问题规模n的关系这里以一层,两层,多层循环为例一层循环for(inti=0;i<n;i++){i......
  • 2024“钉耙编程”中国大学生算法设计超级联赛(1)第一场1001
    循环位移题解2024“钉耙编程”中国大学生算法设计超级联赛(1)题目:ProblemDescription定义字符串S=S0+⋯+Sn−1循环位移k次为S(k)=Skmodn+⋯+Sn−1+S0+⋯+S(k−1)modn。定义[A]=\setA(k),k∈N.给出T组串A,B,询问B有多少个子串在[A]中。Input第一行一个......
  • 刷算法中途复习基础知识
    1.数据类型数据类型分为值传递和引用传递值传递:八大数据类型  Byteshortint long floatdouble charboolean引用传递:类接口 数组其中字符串和枚举类型比较特殊,但是都是基于引用数据类型来实现的.基本数据类型只能存自己类型的值,没有其他额外的功能。引用......
  • java做算法题可以用到的方法(都是很常用的)
    java做算法题可以用到的方法(都是很常用的)数组排序(从小到大)将字符串大写字母转为小写替换字符串中符合某种规则的字符去除字符串两端的空白字符分割字符串将数组转换为列表两数比较取较大/较小的数字int类型转换为String类型赋予int类型一个最大数(算法题中一般用于初始化一......
  • Java 经典排序算法代码 + 注释分析(冒泡、选择、插入、希尔、快排、计数、堆排、归并)
    Java经典排序算法代码+注释分析(冒泡、选择、插入、希尔、快排、计数、堆排、归并)以下是八种经典排序算法的代码,Java8亲测可用,可以直接运行importjava.util.Arrays;publicclassSort{privatestaticfinalint[]nums={3,44,38,5,47,15,36,26,27......
  • 2024信友队蓝润暑期集训提高1班②Day7
    知识总结Tarjan算法Tarjan算法是一种用于计算有向图中强连通分量的算法。Tarjan算法的基本思想是:首先,将图中每个节点标记为未访问。然后,从某个节点开始,对该节点进行DFS,并记录该节点的入度(即该节点的邻居个数)。对于每个节点,如果其入度为0,则说明它是一个根节点,将它标记......
  • 2024“钉耙编程”中国大学生算法设计超级联赛(2)
    Preface最唐氏的一集,前中期被A卡得数次破防红温,后期经典不知道在干嘛摆着摆着就结束了可惜的是徐神最后1h写的B因为两个数组搞反了一直没过,赛后看了眼就过了,这下狠狠地掉Rating了鸡爪丁真构造题,但有人连WA三发怎么回事呢首先不难想到最大化和\(1\)连边的数量,首......
  • 数据结构与算法总结——线性表
    目录2线性表2.1线性表的定义2.2线性表的基本操作2.2顺序表2.2.1顺序表的定义2.2.2顺序表的基本操作2.3链式表2.3.1链表的定义2.3.2链表的分类2.3.3单向链表2.3.3.1结点设计2.3.3.2链表的初始化2.3.3.3数据的插入2.3.3.4数据的删除2.3.3.5销毁链......
  • AES算法
    介绍AES(高级加密标准,AdvancedEncryptionStandard)是一种广泛使用的对称密钥加密算法,由比利时密码学家VincentRijmen和JoanDaemen设计,他们设计的算法最初被称为Rijndael。AES于2001年被美国国家标准与技术研究院(NIST)选为官方的加密标准,用以取代旧的DES标准。以下是AES算法的一......
  • 【动态规划】【官解+整洁度优化+状态压缩-空间优化算法】力扣198.打家劫舍
    你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。给定一个代表每个房屋存放金额的非负整数数组,计算你不触动警报装置的情况下,一夜......