力扣 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