力扣 leetcode 480. 滑动窗口中位数 (python)

Topic

中位数是有序序列最中间的那个数。如果序列的长度是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。
例如:
[2,3,4],中位数是 3
[2,3],中位数是 (2 + 3) / 2 = 2.5
给你一个数组 nums,有一个长度为 k 的窗口从最左端滑动到最右端。窗口中有 k 个数,每次窗口向右移动 1 位。你的任务是找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。

Example

给出 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]。

Solution_1

暴力法解决
每次将滑窗的值加入到新数组num中
之后对num排序

k为奇数的直接将滑窗中间值
k为偶数则返回滑窗中间两值的平均值了

将计算完的中位数加入res数组中返回即是结果

Code_1

class Solution:
    def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
        if k % 2 != 0:
            res = []
            a = (k - 1) // 2
            for i in range(len(nums) - k + 1):
                num = []
                for j in range(k):
                    num.append(nums[i + j])
                num.sort()
                res.append(num[a])

            return res

        elif k % 2 == 0:
            res = []
            a = k // 2 - 1
            for i in range(len(nums) - k + 1):
                num = []
                for j in range(k):
                    num.append(nums[i + j])
                num.sort()
                res.append((num[a] + num[a + 1]) / 2)

            return res

Solution_1(1)

同样我们也可以把判断的过程
简化为(num[k // 2] + num[(k - 1) // 2]) / 2)

若k是奇数则计算两个中间和再除以二
若k是偶数则计算的即是中位数

Code_1(1)

class Solution:
    def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
        res = []
        a = (k - 1) // 2
        for i in range(len(nums) - k + 1):
            num = []
            for j in range(k):
                num.append(nums[i + j])
            num.sort()
            res.append((num[k // 2] + num[(k - 1) // 2]) / 2)

        return res

Result_1

力扣 leetcode 480. 滑动窗口中位数 (python)_第1张图片

Solution_2

利用二分法
使用二分查找库

设置一个window作为窗口,ans作为结果返回
不断遍历nums
将其中的值通过二分查找放在window窗口中

bisect_left函数是新元素会被放置于它相等的元素的前面
bisect_right返回的则是跟它相等的元素之后的位置

通过bisect_left将其放在window中合适的位置
从而保证window递增

当window的长度和k相等时
同方案一将(window[k // 2] + window[(k - 1) // 2]) / 2放在ans中

当window的长度比k大则需要调整窗口window
将window中最早出现的值nums[i - k]命名为a
同时利用bisect_left查找其位置
并将其删除

这里如果用index会大幅降低运行效率
所以用bisect_left查找其上一位
并通过索引加一将其删除

遍历完成nums后返回ans即为结果

Code_2

class Solution:
    def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
        n = len(nums)
        window = []
        ans = []
        
        for i in range(n):
            pos = bisect.bisect_left(window, nums[i])
            window[pos: pos] = [nums[i]]

            if len(window) > k:
                a = nums[i - k]
                pos = bisect.bisect_left(window, a)
                window[pos: pos + 1] = []

            if len(window) == k:
                num = (window[k // 2] + window[(k - 1) // 2]) / 2
                ans.append(num)

        return ans

Result_2

力扣 leetcode 480. 滑动窗口中位数 (python)_第2张图片

你可能感兴趣的:(python,leetcode,二分法,数据结构,python,leetcode,算法)