【Leetcode 二分】 滑动窗口中位数(480)

题目

中位数是有序序列最中间的那个数。如果序列的大小是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。

例如:
[2,3,4],中位数是 3

[2,3],中位数是 (2 + 3) / 2 = 2.5

给出一个数组 nums,有一个大小为 k 的窗口从最左端滑动到最右端。窗口中有 k 个数,每次窗口移动 1 位。你的任务是找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。

例如:

给出 nums = [1,3,-1,-3,5,3,6,7],以及 k = 3

窗口位置                      中位数
---------------               -----
[1  3  -1] -3  5  3  6  7       1
 1 [3  -1  -3] 5  3  6  7      -1
 1  3 [-1  -3  5] 3  6  7      -1
 1  3  -1 [-3  5  3] 6  7       3
 1  3  -1  -3 [5  3  6] 7       5
 1  3  -1  -3  5 [3  6  7]      6

因此,返回该滑动窗口的中位数数组 [1,-1,-1,3,5,6]。

提示:
假设k是合法的,即:k 始终小于输入的非空数组的元素个数.

解答

题目和滑动窗口最大值异常相似

前几天写这道题时一直超时,用的对每个窗口都排序再找中位数,中间每次快排N·log(N) 。。

AC:cur表示当前窗口,每次向右滑动时加入一个新元素,并删除左边元素,再计算中位数。窗口滑动过程中不必每次都重新排序,维护cur有序,新元素用bisect二分插入,删除也用二分查找删。二分复杂度log(N),加上外层遍历,整体复杂度Time: N·log(N),Space: O(N)

这种方法要先排序第一个窗口,记录已排序的cur

2,窗口求中位数用BFPRT应该也能做出来,时间复杂度O(N),窗口数为偶数时,应该要两次BFPRT,复杂度O(2N),总复杂度O(N·K),待更ing...

代码如下:

import bisect


class Solution:
    def medianSlidingWindow(self, nums, k):
        length = len(nums)
        ans = []

        cur = nums[:k]
        left = nums[0]
        cur.sort()
        ans.append(self.getmedian(cur))

        for i in range(1, length - k + 1):
            del_index = bisect.bisect(cur, left) - 1  # 二分找删除元素的位置
            cur.pop(del_index)

            left = nums[i]  # 记录左边元素
            bisect.insort(cur, nums[i + k - 1])  # 二分插入
            ans.append(self.getmedian(cur))
            # print(ans)
        return ans

    def getmedian(self, nums):
        if len(nums) % 2 == 0:
            return (nums[len(nums) // 2] + nums[len(nums) // 2 - 1]) / 2
        return nums[len(nums) // 2]


s = Solution()
print(s.medianSlidingWindow([1, 3, -1, -3, 5, 3, 6, 7], 3))
原文地址:https://www.cnblogs.com/ldy-miss/p/12074326.html