python_14_滑动窗口

1 滑动窗口

窗口只能往右走,L–或R++
时间复杂度o(1)
和首尾指针类似

1.1 窗口题目

假设一个固定大小为w的窗口,依次划过arr,返回每一次划过状况的最大值
例如,arr=[4,3,5,4,3,3,6,7],w=3
返回[5,5,5,4,6,7]

这里双端队列设定是从大向右,越来越小

这里有一个小知识

from collections import deque

引入双端队列,collections 是python工具集合
deque操作

https://blog.csdn.net/jamfiy/article/details/88188595

from collections import deque
def getMaxWindow(arr,w):
    if arr is None or w < 1 or len(arr) < w:  # 长度小于窗口
        return None
    # 双端队列中存放的是位置,arr[位置],队列头部代表数  大->小
    qmax = deque()
    # 最后结果是多少
    res = [0] * (len(arr) - w + 1)   # 观察出来的公式,需要建立这么大数组
    index = 0
    # L...R
    #     i
    # 当前让i -> [i] 进窗口,i就是r
    for R in range(len(arr)):
        # R位置所代表的值,可以放在比他大的数后,或者空
        # 下面是怎么进窗口逻辑
        # 不为空且尾巴值小于等于我,弹到比我大的数后面或弹到空,就停
        l = len(qmax)
        while l != 0 and arr[qmax[l - 1]] <= arr[R]:
            qmax.pop()         # 一直从尾巴弹出
            l = len(qmax)
        qmax.append(R)

        # 数字进来了
        # 如果窗口没有形成w的长度之前,不弹出数字   来到R位置,R-w就是越界数字
        if qmax[0] == R - w:      # 如果双端队列头部位置等于R-w
            qmax.popleft()        # 是越界下标,就从头部弹一个位置

        # 以上窗口更新就做完了

        if R >= w - 1:            # 窗口没有形成w时不收集答案,当达成w时收集长度
            res[index] = arr[qmax[0]]         # 达成长度就收集答案,收集头部值
            index += 1

    return res

arr = [4,3,5,4,3,3,6,7]
w = 3
print(getMaxWindow(arr,w))

1.2 题目2

给定一个整形数组arr,和一个整数num
某个arr中的子数组sub,如果想达标,必须满足:
sub中最大值 - sub中最小值 <= num
返回arr中达标子数组的数量
时间复杂度:O(N)

from collections import deque

def getNum(arr,num):
    if all == None or len(arr) == 0:
        return 0
    qmin = deque()
    qmax = deque()
    L = 0
    R = 0
    # [L...R)    [0,0) [1,1)  代表窗口没有数字
    # [0,1) 代表有一个数
    res = 0      # 一共的数量
    # L是开头位置,尝试每一个开头
    while L < len(arr):

        # 如果此时窗口开头是L,下面的while工作:R向右扩到违规为止
        while R < len(arr):    # R是最后一个达标位置的再下一个

            while len(qmin) != 0 and arr[qmin[-1]] >= arr[R]:  # R位置数进来时,怎么更新
                qmin.pop()  # 一直从尾巴弹出
            qmin.append(R)

            # 最大值更新方式
            while len(qmax) != 0 and arr[qmax[-1]] <= arr[R]:
                qmax.pop()  # 一直从尾巴弹出
            qmax.append(R)

            # 监测是否达标
            if arr[qmax[0]] - arr[qmin[0]] > num:
                break
            R += 1
        # 从上面循环跳出时,R来到了第一个不达标位置,0....R-1 是达标的

        # R是最后一个达标位置的再下一个,第一个违规的位置
        res += R - L    # 累加
        # 最小值的更新结构和最大值的更新结构查看是否过期
        if qmin[0] == L:
            qmin.popleft()
        if qmax[0] == L:
            qmax.popleft()

        L += 1
    return res

arr = [3,4,5,6]
num = 3
print(getNum(arr,num))

2 单调栈

2.1解决:离一个数最近的数,左边是什么,右边是什么

在这里插入图片描述
在这里插入图片描述

from collections import deque

# 为什么返回二维数组呢
# 比如 arr[0 ,2,1,4,5]
#         0  1 2 3 4
#   [
#       0 : [-1,1]    第0行,-1代表左边离它近小于它的数是没有
#       1 : [-1,2]    第1个位置的数
#   ]

def getNearLess(arr):
    res = [[0] * 2 for _ in range(len(arr))]
    # 单调栈放的是位置,同样值的东西,位置压在一起
    # 位置代表值,是从小到大的
    # 准备一个数组 [3,2,3,5,3,1]  对应位置为   0 1 2 3 4 5
    stack = []
    for i in range(len(arr)):        # i->arr[i] 进栈
        # 从底到顶,从小到大            栈顶元素中,列表的第一个位置的值  是否大于当前值  这里是arr[0] = 3 > arr[1] = 2 把整个list弹出
        while len(stack) != 0 and arr[stack[len(stack) - 1][0]] > arr[i]:
            popIs = stack.pop()      # 弹出栈顶列表
            # 取位于下面位置的列表中,最晚加入的那个                    -1 取列表中最后一个
            leftLessIndex = -1 if len(stack) == 0 else stack[-1][-1]
            for popi in popIs:
                res[popi][0] = leftLessIndex            # 左边近且最小
                res[popi][1] = i                        # 右边近且最小

        # 相等的,比你小的
        if len(stack) != 0 and arr[stack[0]] == arr[i]:
            stack[-1].append(i)               # 下标压到列表内
        else:
            list = []    # 生成一个列表
            list.append(i)   # 0放进去 i==0               [1]代表2
            stack.append(list)   # 列表放入栈中

    while len(stack) != 0:  # 栈内还有东西
        popIs = stack.pop()
        # 取位于下面位置的列表中,最晚加入的那个
        leftLessIndex = -1 if len(stack) == 0 else stack[-1][-1]
        for popi in popIs:
            res[popi][0] = leftLessIndex  # 左边近且最小
            res[popi][1] = -1  # 右边开始清算,所以都是-1

    return res

2.2 求子数组最大值是多少

给定一个只包含正整数的数组arr,arr中任何一个子数组sub一定都可以算出(sub累加和)*(sub中的最小值)是什么,
那么所有子数组中,这个值最大是多少?
这也可以用单调栈,范围变大指标变大或变小 —>单调性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值