【刷题】滑动窗口精通 — Leetcode 30. 串联所有单词的子串 | Leetcode 76. 最小覆盖子串

news2024/9/22 4:28:06

在这里插入图片描述
送给大家一句话:

充满着欢乐与斗争精神的人们,永远带着欢乐,欢迎雷霆与阳光。 —— 赫胥黎

滑动窗口精通

  • 前言
  • Leetcode 30. 串联所有单词的子串
    • 题目描述
    • 算法思路
  • Leetcode 76. 最小覆盖子串
    • 题目描述
    • 算法思路
  • Thanks♪(・ω・)ノ 谢谢阅读!!!
  • 下一篇文章见!!!

前言

相信通过前两篇的文章的讲解,大家已经对滑动窗口有了较深的认识,今天我们来挑战一下!!!
来做两道困难级的题目。

Leetcode 30. 串联所有单词的子串

家人们!!!上链接!!!30. 串联所有单词的子串

题目描述

在这里插入图片描述
根据题目描述,这道题看起来很是复杂呢!?!?
我们要在一个字符串中寻找包含words的所有单词的子串,并会返回对应的开始位置(开始索引)。看这描述十分类似这道题目 438. 找到字符串中所有字母异位词 ,一个是寻找异位词,一个是寻找"异位单词串"。本质是十分相似的。
来看一个样例:

  • 输入:s = “barfoothefoobarman”, words = [“foo”,“bar”]
  • 输出:[0,9]
  • 解释:因为 words.length == 2 同时 words[i].length == 3,连接的子字符串的长度必须为 6。
    子串 “barfoo” 开始位置是 0。它是 words 中以 [“bar”,“foo”] 顺序排列的连接。
    子串 “foobar” 开始位置是 9。它是 words 中以 [“foo”,“bar”] 顺序排列的连接。
  • 输出顺序无关紧要。返回 [9,0] 也是可以的。

根据这样例,更容易想象为是如同字母一样。

算法思路

我们先把每个单词抽象为一个字母(方便我们梳理思路),我们只需要找到一个子串中有所有的“字母”即可。
那么,我们来看最简单的算法:暴力枚举。就是遍历所有的子串,以样例来说:

  1. bar foo the foo bar man (注意步长是单词的长度),从左到右依次遍历,寻找满足条件的子串。

  2. 我们来思考一下,当该躺不满足条件时:
    在这里插入图片描述

    很明显,无需把right重新移动的到left的位置重新开始,直接继续进行移动就可以。

  3. 所以此时构成滑动窗口的条件两个指针移动方向一致

那么我们就按照滑动窗口的解题模版来思考细节:

  • 进窗口
  • 判断
  • 出窗口
  • 更新结果(位置待定)

首先我们要解决的是个一般性问题:s 字符串的长度一定是单词的整数倍吗???
显然不是!
那么就要进行多次滑动窗口!保证可以遍历到所有可能的子串。那进行几次呢???
在这里插入图片描述

可以看出来只需要进行单词个数次的循环即可!!!再多就发生重复了!

这样大致的框架就有了,剩下的就是然后判断单词是否满足条件。
依旧时候使用哈希算法,利用无向图来模拟哈希表(string 映射 int)。

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        //预备工作
        //哈希表1
        unordered_map<string,int> hash1;
        for(auto ch : words) hash1[ch] ++; //对words进行处理
        // 基本变量
        int len = words[0].size(); //单词长度(步长) 
        int m = words.size();//单词个数
        int n = s.size();//字符串长度
        //答案
        vector<int> ans;
        //多次进行滑动窗口
        for(int i = 0;i < len;i++)
        {
            //哈希表2 用来进行比较
            unordered_map<string,int> hash2;
            //进窗口 注意一次移动的步长 注意结束条件(保证最后一个是完整单词,不然会发生越界)
            for(int left = i ,right = i ,count = 0; right + len <= n ; right += len )
            {
                string in = s.substr(right,len);
                //进窗口 维护count++ (有效单词数加一)
                if(++hash2[in] <= hash1[in])
                {
                    count++;
                }
                //判断是否超出长度
                if(right - left + 1 > m * len)
                {
                    string out = s.substr(left,len);
                    //出窗口 维护count
                    if(hash2[out]-- <= hash1[out]) count--;
                    left += len;
                }
                //满足条件  更新结果
                if(count == m)
                {
                    ans.push_back(left);
                }
            } 
        }
        return ans;
    }
};

我们提交:过啦!!!!

Leetcode 76. 最小覆盖子串

家人们!!! 上链接!!!76. 最小覆盖子串

题目描述

在这里插入图片描述
根据题目描述,我们需要再字符串中寻找能够覆盖 t 中所有字符的 最短子串,这个“覆盖”是包含 t 中的每个字母,不用管顺序。来看样例:

  • 输入:s = “ADOBECODEBANC”, t = “ABC”
  • 输出:“BANC”
  • 解释:最小覆盖子串 “BANC” 包含来自字符串 t 的 ‘A’、‘B’ 和 ‘C’。

看了样例,应该就理解了这个“覆盖”:

  1. 对应字母个数必须大于等于 t 中字母个数
  2. 可以包含其它字母

算法思路

先来最直接的办法 — 暴力枚举,我们来看暴力算法是如何进行的:

  1. 首先找到一个包含于 t 的字母
  2. 然后从这个位置开始遍历
  3. 直到满足 t 中的每个字母都能在该子串中找到
  4. 然后再找到下一个包含于 t 的字母 重复 1 - 3

这样就完成了任务,那么如何进行优化呢???
根据暴力的步骤,我们可以看出来两个指针的移动方向是一致的,所以就可以进行滑动窗口算法了。
那么我们就按照滑动窗口的解题模版来思考细节:

  • 进窗口
  • 判断
  • 出窗口
  • 更新结果(位置待定)

这个判断要怎样进行判断???
肯定是使用哈希算法,但是如何保证对应字母个数必须大于等于 t 中字母个数呢???
这一步与之前的判断略有不同,因为我们可以多字母,来看代码:

class Solution {
public:
    string minWindow(string s, string t) {
    //滑动窗口 + 哈希算法
    
    //准备工作
    int kinds = 0; //字母种类 方便判断
    int hash1[128] = {0}; //哈希表1 因为只有使用数组比较方便
    //遍历所有字母 确定个数
    for (auto ch : t) 
        if (hash1[ch]++ == 0) kinds++;
    // 长度 
    int n = s.size();
    //哈希表2 用来比较
    int hash2[128] = { 0 }; 
    int begin = -1 ,minlen = INT_MAX;
    for(int left = 0,right = 0 ,count = 0;right < n;right++)
    {
        
        char in = s[right];
        //进窗口 维护count (对应字母相等时更新 保证满足条件 有效字母加一)
        if(++hash2[in] == hash1[in]) count++;
        //判断
        while(count == kinds)
        {
            //更新结果
            if(right - left + 1 < minlen)
            {
                minlen = right - left + 1;
                begin = left;
            }
            char out = s[left];
            //出窗口 维护count (相等时出窗口 有效字母减少)
            if(hash2[out]-- == hash1[out]) count--;
            left++;
        }
    }
    return begin == -1 ? "" : s.substr(begin,minlen);
    }
};

提交:过啦!!!!!!

经过这两道题目的书写,相信大家一定深刻认识到了滑动窗口的使用方法!!!
下面请大家继续刷题吧!!!

Thanks♪(・ω・)ノ 谢谢阅读!!!

下一篇文章见!!!

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

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

相关文章

产品推荐 | 基于 Zynq UltraScale+ XCZU27DR的 FACE-RFSoC-C高性能自适应射频开发平台

一、产品概述 FACE-RFSOC-C自适应射频开发平台&#xff0c;是FACE系列新一代的产品。 平台搭载有16nm工艺的Zynq UltraScale™ RFSoC系列主器件。该器件集成数千兆采样RF数据转换器和ARM Cortex-A53处理子系统和UltraScale可编程逻辑&#xff0c;是一款单芯片自适应射频平台。…

风力发电模型Windpowerlib概述与入门

Windpowerlib 是一个提供了一系列函数和类的库&#xff0c;用于计算风力涡轮机的功率输出。它最初是 feedinlib&#xff08;风能和光伏&#xff09;的一部分&#xff0c;但后来被分离出来&#xff0c;以建立一个专注于风能模型的社区。 这个库的主要目的是简化风力涡轮机的能量…

Vue3 + Vite + TS + Element-Plus + Pinia项目(3)--新建路由

1、在src文件夹下新建router文件夹后&#xff0c;创建index.ts文件 2、具体如下 import { createRouter, createWebHashHistory } from vue-routerconst router createRouter({history: createWebHashHistory(),routes: [{path: "/index",component: () > impor…

红黑树进阶:正向与反向迭代器的实现及map、set的封装实践

文章目录 一、引言二、红黑树迭代器设计1、迭代器的基本概念和分类2、正向迭代器设计a.迭代器结构定义b.迭代器的 与 -- 3、反向迭代器设计a.反向迭代器的必要性b.反向迭代器的实现要点 4、红黑树封装迭代器 三、使用红黑树实现Map四、红黑树实现Set五、细节理解1、 typname的使…

JAVA学习笔记19(面向对象编程)

1.面向对象编程 1.1 类与对象 1.类与对象的概念 ​ *对象[属性]/[行为] ​ *语法 class cat {String name;int age; }main() {//cat1就是一个对象//创建一只猫Cat cat1 new Cat();//给猫的属性赋值cat1.name "123";cat1.age 10; }​ *类是抽象的&#xff0c;…

【Redis系列】那有序集合为什么要同时使用字典和跳跃表

面试官&#xff1a;听说你精通Redis&#xff0c;那我就考考你吧 面试官&#xff1a;不用慌尽管说&#xff0c;错了也没关系&#x1f60a;。。。 以【面试官面试】的形式来分享技术&#xff0c;本期是《Redis系列》&#xff0c;感兴趣就关注我吧❤️ 面试官&#xff1a;你说说Re…

个人可以做知识付费网站吗

个人可以做知识付费网站吗 个人能够做学问付费网站吗&#xff1f;答案是肯定的&#xff01;如今个人做学问付费网站并不需求太多的资金和技术支持&#xff0c;我们只需求购置一台效劳器或虚拟主机&#xff0c;然后在该主机空间上搭建一个WordPress网站&#xff0c;最后运用带有…

商家如何自己零成本免费制作点餐小程序项目完整源码

现在点餐小程序成为餐饮店的标配&#xff0c;顾客只要扫码&#xff0c;即可进入小程序点餐。顾客付款后&#xff0c;后厨自动打印出订单并开始制作。整个过程非常方便流畅&#xff0c;甚至还可以免去收银&#xff08;或服务&#xff09;人员。那么&#xff0c;这种餐饮小程序要…

类和对象三部曲(one)

都说C语言是面向过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用来逐步解决问题。 拿洗衣服来举例&#xff0c;C关注的是一个过程&#xff1a; 那么C是什么呢&#xff1f; 面向对象的编程语言。 面向对象对象指什么&#xff1f; 象棋里的对象么&#xff1f;…

JavaScript学习第二天

1.学习JavaScript高级语法目的 降低后续对于前端框架学习难度 1.局部变量与全局变量 1.局部变量: 在函数体内部通过var声明的变量 1.局部变量特点: 局部变量只能在当前函数体内使用&#xff0c;不能 在函数体外使用 2.全局变量 在script标签下直接…

AI之Suno:Suno V3的简介、安装和使用方法、案例应用之详细攻略

AI之Suno&#xff1a;Suno V3的简介、安装和使用方法、案例应用之详细攻略 目录 Suno AI的简介 1、特点与改进&#xff1a; Suno AI的安装和使用方法 1、第一步&#xff0c;让国产大模型—ChatGLM4帮我写一个提示词 2、第二步&#xff0c;将提示词交给Suno v3&#xff0c;…

LDL^H分解求逆矩阵与MATLAB仿真(Right-Looking)

通过分解将对称正定厄米特矩阵分解成下三角矩阵L和对角矩阵D来求其逆矩阵 目录 前言 一、LDL^H基本算法 二、LDL^H Right-Looking算法 三、D矩阵求逆 四、L矩阵求逆 五、A矩阵求逆 六、计算量分析 七、MATLAB仿真 八、参考资料 总结 前言 在线性代数中&#xff0c;LDL…

如何在Ubuntu系统使用Docker搭建MongoDB结合内网穿透实现公网连接

文章目录 前言1. 安装Docker2. 使用Docker拉取MongoDB镜像3. 创建并启动MongoDB容器4. 本地连接测试5. 公网远程访问本地MongoDB容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 前言 本文主要介绍如何在Linux Ubuntu系统使用Docker快速部署Mon…

企业如何选择一个开源「好」项目?

开源 三句半​​​​​​​ 需求明确是关键 风险考量要周全 开源虽好不白捡 别忘合规&#xff01; 显然&#xff0c;开源已成为一股不可阻挡的洪流&#xff0c;企业拥抱开源&#xff0c;积极参与开源项目不仅是响应技术潮流的必然选择&#xff0c;更是实现自身技术创新、市场拓…

GETSHELL方法总结上

渗透的总步骤 1.信息收集找到弱漏洞 2.漏洞挖掘 漏洞验证 3.有一定权限 getshell 4.提权后---渗透 5.内网渗透】 前后台拿shell方法汇总 接下来我们实操一波dedecms也就是织梦cms 如果你们的靶场是空白的 可能是php版本 我们修改为5.2 可能是源码问题 我们不要急着上传…

【vue核心技术实战精讲】1.6 - 1.8 VUE 指令 (中)

文章目录 前言 本节内容1、v-on使用v-on好处效果 2、事件修饰符2.1、按键码 (<font color red>已废弃&#xff0c;不用研究)示例效果 3、v-for 列表渲染示例效果 前言 上节,我们学习了 Vue指令之v-text 、 v-html、v-if 、v-show、v-bind 点击进入上一节 本节内容 Vue…

【Linux基础】ubuntu虚拟机配置及原理

一、虚拟机 虚拟机&#xff08;Virtual Machine&#xff0c;VM&#xff09;是一种软件实现的计算机系统&#xff0c;它在物理计算机上模拟了一个完整的计算机硬件环境&#xff0c;包括处理器、内存、存储设备和网络接口等。通过虚拟机&#xff0c;用户可以在单个物理计算机上同…

二叉搜索树(二叉排序树,二叉查找树)(附图详解+代码实现+应用分析)

最近学习了有关搜索二叉树的相关知识&#xff0c;在此特意将该知识进行总结分享&#xff0c;希望对大家有所帮助。 文章目录 一.二叉搜索树1.1二叉搜索树的概念1.2二叉搜索树的操作&#xff08;含思路分析代码实现&#xff09;1.2.1二叉搜索树的查找&#xff08;递归实现看最后…

RocketMQ学习笔记:零拷贝

这是本人学习的总结&#xff0c;主要学习资料如下 马士兵教育rocketMq官方文档 目录 1、零拷贝技术1.1、什么是零拷贝1.2、mmap()1.3、Java中的零拷贝 1、零拷贝技术 1.1、什么是零拷贝 使用传统的IO&#xff0c;从硬盘读取数据然后发送到网络需要经过四个步骤。 通过DMA复…

外包干了5年,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入杭州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…