1. 程式人生 > 其它 >力扣 leetcode 480. 滑動視窗中位數 (python)

力扣 leetcode 480. 滑動視窗中位數 (python)

技術標籤:pythonleetcode二分法資料結構pythonleetcode演算法

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

在這裡插入圖片描述

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

在這裡插入圖片描述