从零开始,用堆实现求滑动窗口最大值。
通过维护一个大堆来获取最大值及其下标。
遇到一个值就加入堆,在新添加元素后,如果堆顶元素的下标还在滑动窗口范围内,则获取其值。
否则弹出堆顶元素,至堆顶元素的下标在滑动窗口范围内。
class Solution:
    heap = []
    def __init__(self):
        self.heap = []
    def heapAdjust(self, i, end):
        # 传入根节点下标和边界下标,计算出根节点左孩子下标
        j = 2*i + 1 
        while j <= end: # 左孩子存在
            if j+1 <= end and self.heap[j+1][0] > self.heap[j][0]: # 右孩子存在且更大
                j += 1
            if self.heap[j][0] > self.heap[i][0]: # 孩子比父亲大,交换
                self.heap[j], self.heap[i] = self.heap[i], self.heap[j]
                i = j                             # 更新父子下标,进入下一层
                j = 2*i + 1
            else:
                break         
    def heappush(self, val, idx):
        # 尾插,向上调整,维护一个堆
        self.heap.append((val, idx))
        j = len(self.heap)-1   # 插入元素下标
        while j > 0:
            i = (j-1)//2 # j对应的父节点
            if self.heap[i][0] < self.heap[j][0]: # 孩子大于父亲值,交换
                self.heap[i], self.heap[j] = self.heap[j], self.heap[i]
                j = i    # 更新插入元素的位置
            else:
                break
    def heappop(self):
        # 弹出堆顶元素——最大值
        # 首尾交换
        self.heap[0], self.heap[-1] = self.heap[-1], self.heap[0]
        pop = self.heap.pop()
        self.heapAdjust(0, len(self.heap)-1)
        return pop
    def gettop(self):
        return self.heap[0]
    
    def maxInWindows(self , num: List[int], size: int) -> List[int]:
        if not num: return []
        maxIW = []
        for i in range(len(num)):
            # 先构造大小为size的堆
            if i < size:
                self.heappush(num[i], i)
            else:
                maxIW.append(self.gettop()[0])     # 存入当前堆的最大值
                self.heappush(num[i], i)
                while self.gettop()[1]<=i-size:  # 判断最大值是否在滑动窗口内,如果不在则不断弹出堆顶元素
                    self.heappop()
        maxIW.append(self.gettop()[0])     # 存入当前堆的最大值
        return maxIW