返回

滑动窗口的最大值,详解求解策略与代码实现

前端

前言

在数据结构和算法领域,滑动窗口最大值问题是一个经典且实用的问题。它要求找到一个滑动窗口内的最大元素,该窗口在给定数组上滑动。滑动窗口最大值问题在许多实际应用中都有着广泛的应用,例如:

  • 金融数据分析:识别股票价格或汇率的局部最大值。
  • 流数据处理:查找数据流中最近一段时间内的最大值。
  • 时间序列分析:检测时间序列中异常值或峰值。

解法一:最大堆

最大堆是一种二叉堆,它满足以下性质:

  • 堆中每个节点的值都大于或等于其子节点的值。
  • 堆的根节点是最大值。

我们可以利用最大堆来解决滑动窗口最大值问题。具体步骤如下:

  1. 初始化一个最大堆,并将其容量设置为窗口大小 k。
  2. 将滑动窗口内的元素依次插入最大堆。
  3. 当窗口滑动时,将窗口外的元素从堆中删除,并插入新的元素。
  4. 堆的根节点即为滑动窗口内的最大值。

代码实现(Python):

import heapq

class MaxHeap:
    def __init__(self, k):
        self.heap = []
        self.size = k

    def insert(self, val):
        heapq.heappush(self.heap, val)
        if len(self.heap) > self.size:
            heapq.heappop(self.heap)

    def get_max(self):
        return self.heap[0]

def sliding_window_max(nums, k):
    max_heap = MaxHeap(k)
    result = []
    for i in range(len(nums)):
        max_heap.insert(nums[i])
        if i >= k - 1:
            result.append(max_heap.get_max())
    return result

解法二:双端队列

双端队列(也称为双向链表)是一种特殊的队列,它允许从队列的两端进行插入和删除操作。我们可以利用双端队列来解决滑动窗口最大值问题。具体步骤如下:

  1. 初始化一个双端队列。
  2. 将滑动窗口内的元素依次加入双端队列。
  3. 当窗口滑动时,将窗口外的元素从双端队列中删除,并插入新的元素。
  4. 双端队列的首元素即为滑动窗口内的最大值。

代码实现(Python):

from collections import deque

def sliding_window_max(nums, k):
    window = deque()
    result = []
    for i in range(len(nums)):
        while window and nums[i] > window[-1]:
            window.pop()
        window.append(nums[i])
        if i >= k - 1:
            result.append(window[0])
            if nums[i - k + 1] == window[0]:
                window.popleft()
    return result

性能分析

最大堆和双端队列解法的性能分析如下:

解法 时间复杂度 空间复杂度
最大堆 O(n log k) O(k)
双端队列 O(n) O(k)

其中,n 为数组长度,k 为窗口大小。

对于窗口大小较小的场景,最大堆和双端队列的性能差异不大。但是,对于窗口大小较大的场景,双端队列的性能优势更加明显。

适用场景

最大堆和双端队列解法适用于不同的场景:

  • 如果滑动窗口大小固定且较小,则最大堆解法更适合。
  • 如果滑动窗口大小较大或动态变化,则双端队列解法更适合。

总结

滑动窗口最大值问题是一个经典的数据结构和算法问题。最大堆和双端队列是两种常用的解法,它们具有不同的性能特性和适用场景。在选择具体解法时,需要考虑滑动窗口的大小和实际应用场景。