目录
一、题目
中位数是有序序列最中间的那个数。如果序列的大小是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。
例如:
[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)