📜  数组中滑动窗口的中位数|套装2(1)

📅  最后修改于: 2023-12-03 15:40:03.048000             🧑  作者: Mango

数组中滑动窗口的中位数|套装2

在这个主题里,我们将探讨如何在给定一个整数数组nums和一个大小为k的滑动窗口,通过两种不同的方法来找出滑动窗口中的中位数。

方法一:暴力枚举

我们可以使用暴力枚举的方法来找到每个滑动窗口的中位数。具体来说,我们使用两个指针left和right来表示滑动窗口的左右边界,然后我们将窗口内的元素排序,并计算其中位数。这个方法的时间复杂度为O(nklogk),其中n是数组的长度。

以下是使用暴力枚举找到每个滑动窗口中位数的代码实现:

import bisect

class Solution:
    def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
        n = len(nums)
        if n == 0 or k == 0:
            return []
        if k == 1:
            return [float(x) for x in nums]

        ans = []
        window = sorted(nums[:k])
        for i in range(k, n+1):
            if k % 2 == 0:
                median = (window[k//2] + window[k//2-1]) / 2
            else:
                median = window[k//2]
            ans.append(median)

            if i == n:
                break

            # 删除左端点并插入新元素
            window.pop(bisect.bisect_left(window, nums[i-k]))
            bisect.insort_left(window, nums[i])

        return ans

上述代码使用了Python内置的bisect模块来在排序的数组中查找该删除的元素的索引位置,并使用insort_left方法将新元素插入到正确的位置。

方法二:使用两个堆

使用暴力枚举的方法非常简单,并且易于实现,但如果len(nums)特别大,我们仍然需要O(nklogk)的时间来找到所有滑动窗口的中位数。因此,我们需要使用一种更有效的方法。这里,我们将使用两个堆来解决此问题。

算法的基本思想是在左边的大根堆和右边的小根堆中分别维护滑动窗口中前一半和后一半的元素。在任何时刻,堆的大小不超过k/2。如果k为奇数,则为了保持中位数在左右两个堆中,我们使左堆始终比右堆多一个元素。中位数可以从左边的堆的顶部或两个堆的顶部元素之和中计算出。

以下是使用两个堆找到每个滑动窗口中位数的代码实现:

import heapq

class MedianFinder:
    def __init__(self):
        self.max_heap = []  # 大根堆,保存前一半元素
        self.min_heap = []  # 小根堆,保存后一半元素

    def addNum(self, num: int) -> None:
        # 插入元素并调整两个堆
        if len(self.max_heap) == len(self.min_heap):
            heapq.heappush(self.min_heap, -heapq.heappushpop(self.max_heap, -num))
        else:
            heapq.heappush(self.max_heap, -heapq.heappushpop(self.min_heap, num))

    def findMedian(self) -> float:
        if len(self.max_heap) == len(self.min_heap):
            return (self.min_heap[0] - self.max_heap[0]) / 2
        else:
            return float(self.min_heap[0])

class Solution:
    def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
        n = len(nums)
        if n == 0 or k == 0:
            return []
        if k == 1:
            return [float(x) for x in nums]

        ans = []
        mf = MedianFinder()
        for i in range(n):
            mf.addNum(nums[i])
            if i >= k:
                mf.addNum(nums[i-k])
            if i >= k-1:
                ans.append(mf.findMedian())

        return ans

上述代码使用了Python内置的heapq模块来实现堆的功能。比较两个元素的大小时,我们将正的数加上负号,将问题转换为使用小根堆来处理。这可以将代码的复杂性降至最低。

以上就是我们探讨数组中滑动窗口的中位数|套装2的方法和代码实现,希望对大家有所帮助!