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 value.

Examples:

[2,3,4] , the median is 3

[2,3], the median is (2 + 3) / 2 = 2.5

Given an array nums, 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. Your job is to output the median array for each window in the
original array.

For example,
Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.

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

Therefore, return the median sliding window as [1,-1,-1,3,5,6].

Note:
You may assume k is always valid, ie: k is always smaller than input array's size for non-empty array.

Idea 1: BruteForce, keep the window sorted, if it's even numbers in the window, median = nums[(k-1)/2]/2.0 + nums[k/2]/2.0 to avoid overflow, median = nums[k/2] = nums[(k-1)/2] if k is odd, hence the formula is suitable for both even or odd k.
median = nums[(k-1)/2]/2.0 + nums[k/2]/2.0
 
Time complexity: O(nk), it takes O(k) to remove outside window element and add new element while keeping window sorted
Space complexity: O(k)
 class Solution {
public double[] medianSlidingWindow(int[] nums, int k) {
if(k > nums.length) {
return new double[0];
} double[] result = new double[nums.length - k + 1]; int[] buffer = Arrays.copyOf(nums, k);
Arrays.sort(buffer);
result[0] = buffer[(k-1)/2]/2.0 + buffer[k/2]/2.0; for(int right = k; right < nums.length; ++right) {
int pos = Arrays.binarySearch(buffer, nums[right-k]);
while(pos > 0 && buffer[pos-1] > nums[right]) {
buffer[pos] = buffer[pos-1];
--pos;
} while(pos + 1 < k && buffer[pos+1] < nums[right]) {
buffer[pos] = buffer[pos+1];
++pos;
} buffer[pos] = nums[right];
result[right - k + 1] = buffer[(k-1)/2]/2.0 + buffer[k/2]/2.0;
}
return result;
}
}

python:

 class Solution:
def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
window = sorted(nums[0:k]) medianIndex = k
result = []
result.append(window[(k-1)//2]/2.0 + window[k//2]/2.0) for right in range(k, len(nums)):
window.remove(nums[right-k])
bisect.insort(window, nums[right])
result.append(window[(k-1)//2]/2.0 + window[k//2]/2.0) return result

Idea 2. a. Similar to find median from Data Stream LT295, besides we need to add element to the window, we need to remove element outside of window, the removing action in priority queue in java takes O(n), unless we make customized heap-based priority queue, the alternative choice is TreeSet, to deal with duplicates, use the index for equal elements.

Time complexity: O(nlogk)

Space complexity: O(k)

 class Solution {
public double[] medianSlidingWindow(int[] nums, int k) {
if(k > nums.length) {
return new double[0];
} double[] result = new double[nums.length - k + 1]; Comparator<Integer> cmp = (a, b) -> {
if(nums[a] == nums[b]) {
return a-b;
}
return Integer.compare(nums[a], nums[b]);
};
TreeSet<Integer> maxHeap = new TreeSet<>(cmp);
TreeSet<Integer> minHeap = new TreeSet<>(cmp); for(int right = 0; right < nums.length; ++right) {
maxHeap.add(right);
minHeap.add(maxHeap.pollLast()); if(maxHeap.size() < minHeap.size()) {
maxHeap.add(minHeap.pollFirst());
} if(right >= k-1) {
if(k%2 == 1) {
result[right-k+1] = nums[maxHeap.last()];
}
else {
result[right-k+1] = nums[maxHeap.last()]/2.0 + nums[minHeap.first()]/2.0;
} if(!maxHeap.remove(right-k+1)) {
minHeap.remove(right-k+1);
}
}
} return result;
}
}

Idea 2.b priority queue

Time complexity: O(nk)

Space complexity: O(k)

 class Solution {
public double[] medianSlidingWindow(int[] nums, int k) {
if(k > nums.length) {
return new double[0];
} double[] result = new double[nums.length - k + 1]; PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
PriorityQueue<Integer> minHeap = new PriorityQueue<>(); for(int right = 0; right < nums.length; ++right) {
maxHeap.add(nums[right]);
minHeap.add(maxHeap.poll()); if(maxHeap.size() < minHeap.size()) {
maxHeap.add(minHeap.poll());
} if(right >= k-1) {
if(k%2 == 1) {
result[right-k+1] = maxHeap.peek();
}
else {
result[right-k+1] = maxHeap.peek()/2.0 + minHeap.peek()/2.0;
} if(!maxHeap.remove(nums[right-k+1])) {
minHeap.remove(nums[right-k+1]);
}
}
} return result;
}
}

Idea 2.c. priority queue + hashmap to store elements outside of window, instead of remove elemnts immediately

Time complexity: O(nlogk)

Space complexity: O(n)

 class Solution {
public double[] medianSlidingWindow(int[] nums, int k) {
if(k > nums.length) {
return new double[0];
} double[] result = new double[nums.length - k + 1]; int leftCnt = 0;
int rightCnt = 0;
Map<Integer, Integer> record = new HashMap<>();
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
PriorityQueue<Integer> minHeap = new PriorityQueue<>(); for(int right = 0; right < nums.length; ++right) {
maxHeap.add(nums[right]);
minHeap.add(maxHeap.poll()); if(maxHeap.size() -leftCnt < minHeap.size() - rightCnt) {
maxHeap.add(minHeap.poll());
} if(right >= k-1) {
if(k%2 == 1) {
result[right-k+1] = maxHeap.peek();
}
else {
result[right-k+1] = maxHeap.peek()/2.0 + minHeap.peek()/2.0;
} if(maxHeap.peek() >= nums[right-k+1]) {
if(maxHeap.peek() == nums[right-k+1]) {
maxHeap.poll();
}
else {
record.put(nums[right-k+1], record.getOrDefault(nums[right-k+1], 0) + 1);
++leftCnt;
}
}
else {
if(minHeap.peek() == nums[right-k+1]) {
minHeap.poll();
}
else {
++rightCnt;
record.put(nums[right-k+1], record.getOrDefault(nums[right-k+1], 0) + 1);
}
} while(record.containsKey(maxHeap.peek())) {
int key = maxHeap.poll();
record.put(key, record.get(key)-1);
if(record.get(key) == 0) {
record.remove(key);
}
--leftCnt;
} while(record.containsKey(minHeap.peek())) {
int key = minHeap.poll();
record.put(key, record.get(key)-1);
if(record.get(key) == 0) {
record.remove(key);
}
--rightCnt;
}
}
} return result;
}
}

Sliding Window Median LT480的更多相关文章

  1. [LeetCode] Sliding Window Median 滑动窗口中位数

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  2. Leetcode: Sliding Window Median

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  3. LeetCode 480. Sliding Window Median

    原题链接在这里:https://leetcode.com/problems/sliding-window-median/?tab=Description 题目: Median is the middl ...

  4. 【LeetCode】480. 滑动窗口中位数 Sliding Window Median(C++)

    作者: 负雪明烛 id: fuxuemingzhu 公众号: 每日算法题 本文关键词:LeetCode,力扣,算法,算法题,滑动窗口,中位数,multiset,刷题群 目录 题目描述 题目大意 解题方 ...

  5. LintCode "Sliding Window Median" & "Data Stream Median"

    Besides heap, multiset<int> can also be used: class Solution { void removeOnly1(multiset<in ...

  6. Lintcode360 Sliding Window Median solution 题解

    [题目描述] Given an array of n integer, and a moving window(size k), move the window at each iteration f ...

  7. 滑动窗口的中位数 · Sliding Window Median

    [抄题]: 给定一个包含 n 个整数的数组,和一个大小为 k 的滑动窗口,从左到右在数组中滑动这个窗口,找到数组中每个窗口内的中位数.(如果数组个数是偶数,则在该窗口排序数字后,返回第 N/2 个数字 ...

  8. Sliding Window Median

    Description Given an array of n integer, and a moving window(size k), move the window at each iterat ...

  9. 480 Sliding Window Median 滑动窗口中位数

    详见:https://leetcode.com/problems/sliding-window-median/description/ C++: class Solution { public: ve ...

随机推荐

  1. with check(转)

    假如我要为一个表中添加一个外键约束.语法如下 alter table  dbo.employee with check add constraint [FK_employeeno]  foreign ...

  2. sqlite3调试

    [sqlite3调试] 1.adb shell 激活模拟器shell. 2.cd /data/data/com.xxx.xxx/databases 进入app 数据库目录. 3.ls 查看有哪些数据库 ...

  3. appium API接口

    appium API接口 标签(空格分隔): appium常用api 1.contexts contexts(self) 返回当前会话的上下文,使用可以识别H5页面的控件: driver.contex ...

  4. Numpy:ndarray数据类型和运算

    Numpy的ndarray:一种多维数组对象 N维数组对象,该对象是一个快速而灵活的大数据集容器,nadarry是一个通用的同构数据多维容器,也就是说,其中的所有元素必须是相同类型的.每个数组都有一个 ...

  5. sqlserver 当前时间减去30天

    参考 https://zhidao.baidu.com/question/750666819064717772.html select dateadd(dd,-30,getdate()) from 表 ...

  6. 全国绿色计算大赛 模拟赛第一阶段(C++)第1关:求和

    挑战任务 这次“绿盟杯”大赛,小明作为参赛选手在练习的时候遇到一个问题,他要对一个范围的两个数进行数位的累加,例如有两个数 15,19 则 他们的数位和应该为:1+5+1+6+1+7+1+8+1+9, ...

  7. TOJ3112: 单词串串烧(回溯)

    传送门(<--可以点击的) 时间限制(普通/Java):1000MS/3000MS     内存限制:65536KByte 描述 “单词串串烧”是一款拼词智力游戏,给定4*4的方格,随机取16个 ...

  8. 最小生成树kruskal模板

    算法思路:每次选取权值最小的边,判断这两个点是否在同一个集合内,如果在则跳过,如果不在则加上这条边的权值 可以使用并查集储存结点,可以快速判断结点是否在同一集合内. #include<iostr ...

  9. cipher的各个模式

    block cipher 工作模式(引自百度)Electronic Codebook Mode 最经典的模式,把明文按64比特为单位分为block, 对所有block使用同样的密钥来加密,最后把输出的 ...

  10. stark组件之路由分发【模仿Django的admin】

    一.先看下django的admin是如何进行路由分发的 1.先看下django的admin的url路径有哪些 其实很简单,假如有一个书籍表,那么每张表对应四个url,增.删.改.查 查看的url ht ...