当前位置: 首页 > news >正文

双指针:滑动窗口

题目描述

  • 给定两个字符串 S 和 T,求 S 中包含 T 所有字符的最短连续子字符串的长度,同时要求时间复杂度不得超过 O(n)。

输入输出样例

  • 输入是两个字符串 S 和 T,输出是一个 S 字符串的子串。样例如下:
    在这个样例中, S 中同时包含一个 A、一个 B、一个 C 的最短子字符串是“BANC”。
Input: S = “ADOBECODEBANC”, T = “ABC”
Output: “BANC”

算法步骤

  • 本题使用滑动窗口求解,即两个指针 l 和 r 都是从最左端向最右端移动,且 l 的位置一定在 r 的左边或重合。注意本题虽然在 for 循环里出现了一个 while 循环,但是因为 while 循环负责移动 l 指针,且 l 只会从左到右移动一次,因此总时间复杂度仍然是 O(n)。
  • 先统计 T 中的各字符是否出现及数量,用 flag[i]代表代表ACII值为i的字符是否出现, chars [i] 表示ACII值为i的字符在T中出现的次数,也可以用于表示当前窗口中缺少的字符的数量。
  • cnt 表示当前窗口中的 包含T中字符 的数量,由于后续代码中 cnt 的变化都和 chars 有关(每次chars 变化后,cnt才变换),则可直接用 cnt 的值和 T的大小比较,判断滑动窗口中是否都包含了T中的字符。左指针 l 和右指针 r 开始默认指向字符串最左边的第一个元素。初始化滑动窗口的最小值为整个S的长度+1,即表示整个S字符串都不匹配。
  • 接下来的 for 外层循环 负责移动窗口的 右指针r 来遍历字符串 S,若 S[r] 不是T中的字符,则不做处理, r 往右遍历;若 S[r] 是T中的字符,则进行以下处理:
    • 判断 当前窗口中是否还缺少字符 S[r] ,若缺少,则 cnt++。
    • 若 cnt 的值等于 T 的大小,则表示当前滑动窗口中已经包含了 T 中所有字符,然后进入while 内层循环,负责移动左指针 l:将 左指针l 右移,在不影响结果的情况收缩窗口,以获得最短子字符串。
      • 若当前滑窗长度 < 最小长度,则刷新最小长度和左指针 l。
      • 若 左指针指向的字符 S[l] 属于T中的字符,且++chars[S[l]] > 0即左指针再往后移的话滑动窗口就不再满足条件,表示此时已是 当前 r 遍历条件下的最小窗口,然后将 cnt-- 表示后续将 l 右移一步的话,滑动窗口内T中的字符数量将少1。
      • 左指针 l 继续右移一步向后遍历。
  • 最后判断滑动窗口的长度,若大于S的长度表示整个S都不匹配返回空,否则进行切片处理返回字符串S中左指针和右指针所截取的窗口内容。

PS:为什么左指针只需要从左到右 右移一次即可,不需要在每次 右指针r 遍历的情况下将左指针从左到右重新右移一遍?
答:在 r 时,遍历到的最小滑窗窗口比如说 [l,p] ,长度是 p-l+1,r≥p。
在 r+1 时,若想要遍历到更小的窗口,则滑动窗口的左指针只能继续往后移,因为前面已经确定最小的滑动窗口。

#include <iostream>
#include <vector>
using namespace std;
string minWindow(string S, string T) {vector<int>  chars(128, 0);     // ASCII表共128个字符,chars[i]代表ACII值为i的字符在T中出现的次数vector<bool> flag(128, false);  // flag[i]代表代表ACII值为i的字符是否出现// 先统计T中的字符情况for (int i = 0; i < T.size(); ++i) {flag[T[i]] = true;++chars[T[i]];}// 移动滑动窗口, 不断更改统计数据int cnt = 0, l = 0, min_l = 0, min_size = S.size() + 1;for (int r = 0; r < S.size(); ++r) { //接下来的外层循环通过移动窗口的右边界r来遍历字符串S。if (flag[S[r]]) { //若S[r]是T中的字符if (--chars[S[r]] >= 0) { //若当前窗口中还缺该字符,则cnt++++cnt;}// 若目前滑动窗口已包含T中全部字符,// 则尝试将l右移, 在不影响结果的情况下获得最短子字符串while (cnt == T.size()) {if (r - l + 1 < min_size) { // 当前滑窗长度 < 最小长度min_l = l;min_size = r - l + 1;}if (flag[S[l]] && ++chars[S[l]] > 0) { // 当前l缩进的窗口已经最小,不再满足条件cnt--;}++l; //左指针右移}}}return min_size > S.size() ? "" : S.substr(min_l, min_size);
}int main() {string S = "ADOBECODEBANC", T = "ABC";cout << minWindow(S,T);return 0;
}

在这里插入图片描述

http://www.lryc.cn/news/453965.html

相关文章:

  • 云原生(四十八) | Nginx软件安装部署
  • 【WPF开发】如何设置窗口背景颜色以及背景图片
  • USB 3.0?USB 3.1?USB 3.2?怎么区分?
  • Gitlab实战教程:打造企业级代码托管与协作平台!
  • 更新C语言题目
  • struct和C++的类
  • 【数据结构与算法】LeetCode:图论
  • YOLOv8 基于NCNN的安卓部署
  • 【Python|接口自动化测试】使用requests发送http请求时添加headers
  • 需求管理工具Jama Connect:与Jira/Slack/GitHub无缝集成,一站式解决复杂产品开发中的协作难题
  • CSP-J/S 复赛算法 背包DP
  • 如何评估和部署 IT 运维系统?
  • 正态分布的极大似然估计一个示例,详细展开的方程求解步骤
  • s7-200SMART编程软件下载
  • Linux驱动开发常用调试方法汇总
  • 将列表中的各字符串sn连接成为一个字符串s使用;将各sn间隔开os.pathsep.join()
  • 算法题总结(八)——字符串
  • 大数据开发--1.2 Linux介绍及虚拟机网络配置
  • 2024CSP-J复赛易错点
  • pytorch 与 pytorch lightning, pytorch geometric 各个版本之间的关系
  • Spring Boot项目的创建与使用
  • pytorch常用函数view、sum、sequeeze、cat和chunk
  • 【STM32开发之寄存器版】(四)-独立看门狗IWDG
  • 【S32K3 RTD MCAL 篇1】 K344 KEY 控制 EMIOS PWM
  • 华为OD机试真题---绘图机器(计算面积)
  • HarmonyOs 查看官方文档使用弹窗
  • uniapp+Android智慧居家养老服务平台 0fjae微信小程序
  • 在一台电脑上实现网页与exe程序使用udp通信
  • 基于Java的GeoTools对Shapefile文件属性信息深度解析
  • 付费计量系统实体和接口(1)