当前位置:首页 > 题解目录 > 正文内容

【算法】滑动窗口2—窗口大小可变

亿万年的星光2个月前 (02-28)题解目录273

对于滑动窗口第二类:窗口大小可变类型 


图解如下,类似双指针算法。




【解题思想】

  1. 1、字符串 S 中使用双指针的左右指针技巧,初始化 left = right = 0,把索引的左闭右开区间 [left,right) 称为一个「窗口」。

  2. 2、先不断增加 right 指针扩大窗口[left, right)(也就是 right++),直到窗口中的字符串符合要求:包含 T 中所有字符。

  3. 3、停止增加 right ,转而不断增加 left 指针缩小窗口[left, right)(也就是 left++),直到窗口中的字符串不再符合要求:不包含 T 中所有字符。

  4. 4、同时,每增加 left,都要更新一轮结果

  5. 5、重复 2 & 3 步骤,直到 right 到达字符串 S 的尽头

  6. 6、第 2 步骤寻找「可行解」(符合要求),第 3 步骤优化「可行解」(找最短),最终找到「最优解」(最短的覆盖子串)。

  7. 7、左右指针轮流前进,窗口大小增增减减,窗口不断向右滑动,这就是「滑动窗口」名字的来历。


例题1:最长无重复子串

【题目描述】给定一个字符串,找到最长无重复字符的子串。

【样例输入1】abcabcbb

【样例输出1】3

【样例1解释】

输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。


【样例输入2】bbbbb

【样例输出2】1

【样例2解释】

输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

【题目分析】

(1)什么是子串?

  • 子串是字符串中连续的一段字符。

  • 例如,字符串 "abcabcbb" 的子串包括 "abc""bca""cbb" 等。

(2)什么是无重复字符的子串?

  • 无重复字符的子串是指子串中的所有字符都是唯一的,没有重复。

  • 例如,子串 "abc" 是无重复字符的,而子串 "abca" 包含重复字符 'a'

(3)什么是最长无重复字符的子串?

  • 在所有无重复字符的子串中,找到长度最长的那个。

  • 例如,字符串 "abcabcbb" 的最长无重复字符子串是 "abc",长度为 3。


【参考代码】

#include <iostream>
#include <cstring> // 用于 memset

using namespace std;

int ws(string s) {
    int n = s.size();
    int window[256]; // 用于存储字符的最近出现位置
    memset(window, -1, sizeof(window)); // 初始化为 -1
    int left = 0, right = 0; // 窗口的左右边界
    int maxLen = 0;
    while (right < n) {
        char currentChar = s[right];
        if (window[currentChar] != -1 && window[currentChar] >= left) {
            // 如果字符在窗口中,收缩左边界
            left = window[currentChar] + 1;
        }
        // 更新字符的最近出现位置
        window[currentChar] = right;
        // 更新最大长度
        maxLen = max(maxLen, right - left + 1);
        right++;
    }
    return maxLen;
}

int main() {
   	string s;
   	cin>>s;//abcabcbb
	cout<< ws(s) << endl;
    return 0;
}


【解释】

  • (1)使用数组 window 存储字符的最近出现位置。

  • (2)如果字符在窗口中,收缩左边界;否则,扩展右边界。

  • (3)时间复杂度:O(n)


例题2:最大子数组和

【题目描述】给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

【样例输入1】

-2,1,-3,4,-1,2,1,-5,4

【样例输出1】

6


类似题目:【算法】最大子段和 - 青少年编程知识记录


【解题思路】

  1. 维护一个窗口,窗口内的元素和表示当前子数组的和。

  2. 如果当前窗口的和小于 0,则丢弃当前窗口,重新开始计算。

  3. 在遍历过程中,记录窗口和的最大值。

int maxSubArray(int n) {
    int maxSum = INT_MIN; // 记录最大和,初始化为最小整数值
    int currentSum = 0;   // 记录当前窗口的和
    for (int i = 0; i < n; i++) {
        currentSum += nums[i]; // 将当前元素加入窗口
        // 如果当前和大于最大和,更新最大和
        if (currentSum > maxSum) {
            maxSum = currentSum;
        }
        // 如果当前和小于 0,则丢弃当前窗口,重新开始
        if (currentSum < 0) {
            currentSum = 0;
        }
    }
    return maxSum;
}


例题3:最小覆盖子串

难度提升

【题目描述】给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回-1 

【样例输入1】

ADOBECODEBANC
ABC

【样例输出1】

BANC

【样例1解释】

最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。

【样例输入2】

a
a

【样例输出2】

a

【样例2解释】

整个字符串 s 是最小覆盖子串

【样例输入3】

a
aa

【样例输出3】

-1

【样例3解释】

t 中两个字符 'a' 均应包含在 s 的子串中,因此没有符合条件的子字符串,返回-1

【注意】

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。

  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。








扫描二维码推送至手机访问。

版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

分享给朋友:

相关文章

【题解】感应门

【题目描述】感应门会在有人经过的时候自动打开,冷却d 秒后自动关闭。如果有人在感应门打开的状态下通过,那么冷却时间会重置,重新冷却d秒后再关闭。在一段时间内,有 n个人陆续通过了感应门,他们...

【题解】最小子序列

【题目描述】给你一个数组 nums,请你从中抽取一个子序列,满足该子序列的元素之和 严格 大于未包含在该子序列中的各元素之和。如果存在多个解决方案,只需返回 长...

【题解】母牛的故事

【题解】母牛的故事

【题目描述】有一头母牛,它每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。请编程实现在第n年的时候,共有多少头母牛?【输入描述】输入数据由多个测试实例组成,每个测试实例占一行...

亲和数

【题目描述】自然数a的因子是指能整除a的所有自然数,但不含a本身。例如12的因子为:1,2,3,4,6。若自然数a的因子之和为b,而且b的因子之和又等于a,则称a,b为一对“亲和数” 。求最小的一对亲...

【题解】公交乘车

【题解】公交乘车

【题目描述】A城市有一条非常特别的街道,该街道在每个公里的节点上都有一个公交车站,乘客可以在任意的公交站点上车,在任意的公交站点下车。乘客根据每次乘坐公交的公里数进行付费,比如,下表就是乘客乘坐不同的...

【题解】队列问题

【题解】队列问题

4.队列问题(lru.cpp)【题目描述】有一个大小为n的页面缓存队列,初始为空,当计算机访问页面时,若缓存队列没有该页面,则加入到缓存队列中,若队列已满,则将删除访问时间最远的页面。有Q次询问,每次...