[LeetCode] 480. Sliding Window Median

The median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle values.

  • For examples, if arr = [2,3,4], the median is 3.
  • For examples, if arr = [1,2,3,4], the median is (2 + 3) / 2 = 2.5.

You are given an integer array nums and an integer k. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.

Return the median array for each window in the original array. Answers within 10-5 of the actual value will be accepted.

Example 1:

Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [1.00000,-1.00000,-1.00000,3.00000,5.00000,6.00000]
Explanation: 
Window position                Median
---------------                -----
[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

Example 2:

Input: nums = [1,2,3,4,2,3,1,4,2], k = 3
Output: [2.00000,3.00000,3.00000,3.00000,2.00000,3.00000,2.00000]

Constraints:

  • 1 <= k <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1

滑动窗口中位数。

中位数是有序序列最中间的那个数。如果序列的长度是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。

例如:

[2,3,4],中位数是 3
[2,3],中位数是 (2 + 3) / 2 = 2.5
给你一个数组 nums,有一个长度为 k 的窗口从最左端滑动到最右端。窗口中有 k 个数,每次窗口向右移动 1 位。你的任务是找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/sliding-window-median
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这个题的思路跟295题非常像,也是需要用到优先队列。

首先创建一个长度为 len - k + 1 的数组记录结果(这个长度根据例子应该很好推算),一个最大堆,一个最小堆。之后开始遍历 input,类似295题的思路,根据两个堆目前元素个数谁多谁少决定当前数字应该怎么被放入堆中。原则上还是保证两个堆一样大或者最大堆多一个元素

  • 如果最小堆 size 较大或者两者 size 一样,则将当前数字放入最大堆
  • 如果最大堆 size 较大,则将当前数字放入最小堆

之后判断如果两个堆中存放的元素个数达到 K 了,此时就可以开始结算了。注意结算最后记得移除 sliding window 的最左边的元素。

时间O(nlogk)

空间O(n)

Java实现

 1 class Solution {
 2     public double[] medianSlidingWindow(int[] nums, int k) {
 3         double[] res = new double[nums.length - k + 1];
 4         PriorityQueue<Integer> left = new PriorityQueue<>(Collections.reverseOrder());
 5         PriorityQueue<Integer> right = new PriorityQueue<>();
 6         for (int i = 0; i < nums.length; i++) {
 7             if (left.size() <= right.size()) {
 8                 right.add(nums[i]);
 9                 left.add(right.remove());
10             } else {
11                 left.add(nums[i]);
12                 right.add(left.remove());
13             }
14             if (left.size() + right.size() == k) {
15                 double median;
16                 if (left.size() == right.size()) {
17                     median = (double) ((long) left.peek() + (long) right.peek()) / 2;
18                 } else {
19                     median = (double) left.peek();
20                 }
21                 int start = i - k + 1;
22                 res[start] = median;
23                 if (!left.remove(nums[start])) {
24                     right.remove(nums[start]);
25                 }
26             }
27         }
28         return res;
29     }
30 }

 

相关题目

295. Find Median from Data Stream

480. Sliding Window Median

LeetCode 题目总结

posted @ 2020-06-08 07:15  CNoodle  阅读(341)  评论(0编辑  收藏  举报