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

本文主要是介绍【刷题】滑动窗口精通 — Leetcode 30. 串联所有单词的子串 | Leetcode 76. 最小覆盖子串,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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

滑动窗口精通

  • 前言
  • 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) {//预备工作//哈希表1unordered_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);//出窗口 维护countif(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♪(・ω・)ノ 谢谢阅读!!!

下一篇文章见!!!

这篇关于【刷题】滑动窗口精通 — Leetcode 30. 串联所有单词的子串 | Leetcode 76. 最小覆盖子串的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/846507

相关文章

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

C#实现获得某个枚举的所有名称

《C#实现获得某个枚举的所有名称》这篇文章主要为大家详细介绍了C#如何实现获得某个枚举的所有名称,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... C#中获得某个枚举的所有名称using System;using System.Collections.Generic;usi

通过C#获取PDF中指定文本或所有文本的字体信息

《通过C#获取PDF中指定文本或所有文本的字体信息》在设计和出版行业中,字体的选择和使用对最终作品的质量有着重要影响,然而,有时我们可能会遇到包含未知字体的PDF文件,这使得我们无法准确地复制或修改文... 目录引言C# 获取PDF中指定文本的字体信息C# 获取PDF文档中用到的所有字体信息引言在设计和出

mysql-8.0.30压缩包版安装和配置MySQL环境过程

《mysql-8.0.30压缩包版安装和配置MySQL环境过程》该文章介绍了如何在Windows系统中下载、安装和配置MySQL数据库,包括下载地址、解压文件、创建和配置my.ini文件、设置环境变量... 目录压缩包安装配置下载配置环境变量下载和初始化总结压缩包安装配置下载下载地址:https://d

vue解决子组件样式覆盖问题scoped deep

《vue解决子组件样式覆盖问题scopeddeep》文章主要介绍了在Vue项目中处理全局样式和局部样式的方法,包括使用scoped属性和深度选择器(/deep/)来覆盖子组件的样式,作者建议所有组件... 目录前言scoped分析deep分析使用总结所有组件必须加scoped父组件覆盖子组件使用deep前言

Python绘制土地利用和土地覆盖类型图示例详解

《Python绘制土地利用和土地覆盖类型图示例详解》本文介绍了如何使用Python绘制土地利用和土地覆盖类型图,并提供了详细的代码示例,通过安装所需的库,准备地理数据,使用geopandas和matp... 目录一、所需库的安装二、数据准备三、绘制土地利用和土地覆盖类型图四、代码解释五、其他可视化形式1.

bat脚本启动git bash窗口,并执行命令方式

《bat脚本启动gitbash窗口,并执行命令方式》本文介绍了如何在Windows服务器上使用cmd启动jar包时出现乱码的问题,并提供了解决方法——使用GitBash窗口启动并设置编码,通过编写s... 目录一、简介二、使用说明2.1 start.BAT脚本2.2 参数说明2.3 效果总结一、简介某些情

基于Redis有序集合实现滑动窗口限流的步骤

《基于Redis有序集合实现滑动窗口限流的步骤》滑动窗口算法是一种基于时间窗口的限流算法,通过动态地滑动窗口,可以动态调整限流的速率,Redis有序集合可以用来实现滑动窗口限流,本文介绍基于Redis... 滑动窗口算法是一种基于时间窗口的限流算法,它将时间划分为若干个固定大小的窗口,每个窗口内记录了该时间

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

poj2406(连续重复子串)

题意:判断串s是不是str^n,求str的最大长度。 解题思路:kmp可解,后缀数组的倍增算法超时。next[i]表示在第i位匹配失败后,自动跳转到next[i],所以1到next[n]这个串 等于 n-next[n]+1到n这个串。 代码如下; #include<iostream>#include<algorithm>#include<stdio.h>#include<math.