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

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

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


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




【解题思想】

  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 中存在这样的子串,我们保证它是唯一的答案。








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

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

分享给朋友:
返回列表

上一篇:【题解】黑色联通块

没有最新的文章了...

相关文章

大象喝水

【题目描述】上课的时候老师问了小蒜蒜和同学们一个问题:一只大象口渴了,要喝 20 升水才能解渴,但现在只有一个深 h 厘米,底面半径为 r厘米的小圆桶...

【题解】结构体与闰年

【题目描述】定义一个结构体变量(包括年、月、日)。计算该日在本年中是第几天,注意闰年问题。【输入描述】年月日【输出描述】当年第几天【样例输入】2000 12 31【样例输出】366...

【题解】加密(2019青岛市程序设计竞赛)

【问题描述】文件加密最简单的方法是把文件的原文中的每个字母用另一个字母来代替。假设原文中只包括26个英文字母(有大写和小写),没有其他符号,且长度不超过100,加密规则如下:原文abcdefghijk...

【题解】链表操作

【题目描述】给定一个N个数的数组,M次操作,每次操作为下列操作之一。求最后的数组。操作1:在第X个数之后插入一个数Y。操作2:删除第X个数。操作3:对区间[X,Y]进行排序。操作4:对区间[X,Y]进...

【题解】零花钱

零花钱(money.cpp) 【问题描述】 商店里有一件玩具,今天你偶然得知:这件玩具在后⾯的n天里每天的定价(价格可能每天都会改 变),你买了这件玩具后可以以当天的价格卖给商店,...

【题解】种花问题

【题目描述】假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。给你一个整数数组 flowerbed 表示花坛,...