LeetCode480:滑動視窗中位數
技術標籤:LeetCode演算法資料結構pythonleetcode二分查詢
目錄
一、題目
中位數是有序序列最中間的那個數。如果序列的大小是偶數,則沒有最中間的數;此時中位數是最中間的兩個數的平均數。
例如:
[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]。
三、思路
1、暴力法
暴力法很直接且易懂。
tmp 陣列為我們視窗中的數字組成,每次對 tmp 進行排序,利用python中的內建函式sort()函式
2、二分法
python中的 bisect 模組包含兩個主要函式, bisect 和 insort兩個函式都利用二分查詢演算法來在有序序列中查詢或插入元素。
因此我們在排序上進行優化。
這裡我們用到了bisect_left() 函式和insort() 函式 :
bisect_left函式是新元素會被放置於它相等的元素的前面;
insort(seq, item) 把變數 item 插入到序列 seq 中,並能保持 seq 的升序順序。
最後,找出中位數即可。
四、程式碼
1、
class Solution: def medianSlidingWindow(self, nums, k: int): """ :param nums: List[int] :param k: int :return: List[float] """ ans = [] left, right = 0, k - 1 for right in range(k - 1, len(nums)): tmp = nums[left: right + 1] tmp.sort() if k % 2 == 0: ans.append((tmp[(k + 1) // 2 - 1] + tmp[(k + 1) // 2]) / 2) left += 1 else: ans.append(tmp[(k + 1) // 2 - 1]) left += 1 return ans if __name__ == '__main__': nums = [1, 3, -1, -3, 5, 3, 6, 7] k = 3 s = Solution() ans = s.medianSlidingWindow(nums, k) print(ans)
2、
class Solution:
def medianSlidingWindow(self, nums, k: int):
import bisect
ans = []
tmp = []
left, right = 0, k - 1
for right in range(len(nums)):
bisect.insort(tmp, nums[right]) # 利用二分查詢演算法來在有序序列中插入元素
if len(tmp) > k:
tmp.pop(bisect.bisect_left(tmp, nums[left])) # 利用二分查詢演算法來在有序序列中查詢元素
left += 1
if len(tmp) == k:
if k % 2 == 0:
ans.append((tmp[(k + 1) // 2 - 1] + tmp[(k + 1) // 2]) / 2)
else:
ans.append(tmp[(k + 1) // 2 - 1])
return ans
if __name__ == '__main__':
nums = [1, 3, -1, -3, 5, 3, 6, 7]
k = 3
s = Solution()
ans = s.medianSlidingWindow(nums, k)
print(ans)