滑动窗口(尺取法/Python)

滑动窗口(尺取法)

算法含义:

在解决关于区间特性的题目时保存搜索区间左右端点,然后根据实际要求不断更新左右端点位置的算法

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)

在历年真题中,滑动窗口主要有求追偿不重复子串和模拟优先队列求区间最值两个作用

一、求最长不重复字串

不重复子串:字符串的字串中不包含重复字符的字串

py 复制代码
from collections import defaultdict

s = input()
n = len(s)
# 建立一个字典存储各个元素在窗口中出现的次数
d = defaultdict(int)
ans = 0
# 确定窗口左端
left = 0
for right in range(n):
    # 如果发现窗口中已经有s[right],将left右移直到窗口中不存在s[right]
    while d[s[right]] > 0:
        # 更新字典
        d[s[left]] -= 1
        left += 1
    ans = max(ans, right-left+1)

print(ans)

二、模拟优先队列求区间最值

滑动窗口研究区间的性质,可以用于模拟优先队列从而高效求出区间内的最大值和最小值

例题 1: 附近最小(蓝桥杯第14届省模拟赛)
问题描述:

小蓝有一个序列 a [ 1 ] , a [ 2 ] , . . . , a [ n ] a[1],a[2],...,a[n] a[1],a[2],...,a[n]。给定一个正整数 k,请问对于每一个 1 到 n 之间的正整数i, a [ i − k ] , a [ i − k + 1 ] , . . . , a [ i + k ] a[i−k],a[i−k+1],...,a[i+k] a[i−k],a[i−k+1],...,a[i+k] 这 2k+1 个数中的最小值是多少?

当某个下标超过 1 到 n 的范围时,数不存在,求最小值时只取存在的那些值。

输入格式:

输入的第一行包含一整数 n,第二行包含 n 个整数,分别表示 a [ 1 ] , a [ 2 ] , . . . , a [ n ] a[1],a[2],...,a[n] a[1],a[2],...,a[n]。第三行包含一个整数 k

输出格式

输出一行,包含 n 个整数,分别表示对于每个序号求得的最小值。

代码示例:

py 复制代码
# 滑动窗口 + 优先队列
n = int(input())
a = [int(i) for i in input().split()]
k = int(input())
# 在数组右边补k个一定不是最小值的数以免分类讨论
a = a + [a[n-1]+1]*k
d = k*2+1 # 窗口宽度
ans = []
q = []  # 递增的优先队列
# 注意i是滑动窗口的右端点
for i in range(n+k):
    # 如果队列不为空,将所有大于当前元素的队尾元素出队
    while q and a[q[-1]] > a[i]:
        q.pop()
    # 将新元素的下标入队
    q.append(i)
    # 检查队头元素是否在新区间范围内
    if i - q[0] > d-1:
        q.pop(0)
    # 将队头元素记录下来
    if i >= k:
        ans.append(a[q[0]])

# print answer
print(' '.join(list(map(str, ans))))

例题 2: 子矩阵(蓝桥杯第14届省赛真题)
问题描述:

给定一个n x m(n行m列)的矩阵。设一个矩阵的价值为其所有数中的最大值和最小值的乘积。求给定矩阵的所有大小为 a x b (a行b列)的子矩阵的价值的和。答案可能很大,你只需要输出答案对 998244353 取模后的结果。

输入格式:

输入的第一行包含四个整数分别表示n,m,a,b,相邻整数之间使用一个空格分隔。接下来

n行每行包含m个整数,相邻整数之间使用一个空格分隔,表示矩阵中的每个数 A i j A_{ij} Aij。

输出格式

输出一行包含一个整数表示答案。

py 复制代码
# 利用滑动窗口模拟优先队列,从而将搜索每一个区间中最值的时间复杂度从O(n*n)优化为O(n)
MOD = 998244353
def get_max(nums,step):
    # the variable called step store the size of interval
    q = []
    max_list = []
    for i in range(len(nums)):
        while q and nums[q[-1]] < nums[i]:
            # when the end element of prior-quee is small than the new element
            # pop out the end element
            q.pop(-1)
        # the list store the index of every number because it is more convenient to find 
        # out whether the index is out of the interval or not 
        q.append(i)
        # when the first element is out of the range of interval, pop it out
        if q[0] <= i-step:
            q.pop(0)
        # when the queue has been built, add the first element into the answer list
        if i >= step-1:
            max_list.append(nums[q[0]])
    return max_list
# using the same theory,we can find out the minist number
def get_min(nums,step):
    q = []
    min_list = []
    for i in range(len(nums)):
        while q and nums[q[-1]] > nums[i]:
            q.pop(-1)
        q.append(i)
        if q[0] <= i-step:
            q.pop(0)
        if i >= step-1:
            min_list.append(nums[q[0]])
    return min_list
# similarly,we can calculate out the sum of all the numbers in the interval
def get_sum(nums,step):
    sum_list = []
    temp = 0
    # the pointer called i is actually the right pointer
    # the left pointer's value is i-step+1
    for i in range(len(nums)):
        if i < step - 1:
            temp += nums[i]
        elif i == step-1:
            temp += nums[i]
            sum_list.append(temp)
        else:
            temp -= nums[i-step]
            temp += nums[i]
            sum_list.append(temp)
    return sum_list

# the main part of the algorithm
# firstly,use the function to find out all the line's extremum
n,m,a,b = map(int,input().split())
matrix = []
for i in range(n):
    matrix.append([int(j) for j in input().split()])
# zip the row
m_max_one = []
m_min_one = []
for i in range(n):
    m_max_one.append(get_max(matrix[i], b))
    m_min_one.append(get_min(matrix[i], b))
# transpose the temporary matrix and zip again
# the result is the collection of extremum matrix
m_max_two = [[0]*n for i in range(len(m_max_one[0]))]
m_min_two = [[0]*n for i in range(len(m_min_one[0]))]
for i in range(len(m_max_one[0])):
    for j in range(len(m_max_one)):
        m_max_two[i][j] = m_max_one[j][i]
        m_min_two[i][j] = m_min_one[j][i]
# zip the col
m_max = []
m_min = []
for i in range(len(m_max_two)):
    m_max.append(get_max(m_max_two[i], a))
    m_min.append(get_min(m_min_two[i], a))
# calculate the sum of all the sub_matrixs' value
res = 0
for i in range(len(m_max)):
    for j in range(len(m_max[0])):
        res += m_max[i][j]*m_min[i][j]
        res %= MOD
print(res)
相关推荐
Swift社区7 分钟前
Excel 列名称转换问题 Swift 解答
开发语言·excel·swift
一道微光10 分钟前
Mac的M2芯片运行lightgbm报错,其他python包可用,x86_x64架构运行
开发语言·python·macos
矛取矛求15 分钟前
QT的前景与互联网岗位发展
开发语言·qt
Leventure_轩先生15 分钟前
[WASAPI]从Qt MultipleMedia来看WASAPI
开发语言·qt
向宇it29 分钟前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎
m0_7482567837 分钟前
WebGIS实战开源项目:智慧机场三维可视化(学习笔记)
笔记·学习·开源
四口鲸鱼爱吃盐38 分钟前
Pytorch | 利用AI-FGTM针对CIFAR10上的ResNet分类器进行对抗攻击
人工智能·pytorch·python
红色的山茶花41 分钟前
YOLOv9-0.1部分代码阅读笔记-loss.py
笔记
是娜个二叉树!1 小时前
图像处理基础 | 格式转换.rgb转.jpg 灰度图 python
开发语言·python
互联网杂货铺1 小时前
Postman接口测试:全局变量/接口关联/加密/解密
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·postman